In Python, because of the ability to dynamically modify anything it can be very tricky to map back to a source definition. The definition, after all, could be created on the fly.
Here's a somewhat simplistic example. Dynamic definitions can be much trickier even than this, and it's especially tricky if implementation occurs in a pre-compiled module.
def make_random_function(coin='Heads'):
if coin == 'Heads':
def foo(self, a):
print a
elif coin == 'Tails':
def foo(self, a, b):
return a + b
else:
def foo(self, *args, **kwargs):
raise ValueError('Invalid coin used to create function.')
foo.__name__ = "dynamic_foo"
foo.__doc__ = "Good luck buddy."
return foo
import random
val = random.random()
if val > 0.51:
coin = 'Heads'
elif val < 0.49:
coin = 'Tails'
else:
coin = 'Trick'
function = make_random_function(coin)
MyType = type("MyType", (object,), {function.__name__:function})
m = MyType()
When I run this and then call m.dynamic_foo()
I see this:
In [313]: coin
Out[313]: 'Trick'
In [314]: val
Out[314]: 0.5099718112195031
In [315]: m.dynamic_foo()
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-315-70b3caeb205b> in <module>()
----> 1 m.dynamic_foo()
<ipython-input-310-475ea0810d8d> in foo(*args, **kwargs)
8 else:
9 def foo(*args, **kwargs):
---> 10 raise ValueError('Invalid coin used to create function.')
11
12 foo.__name__ = "dynamic_foo"
ValueError: Invalid coin used to create function.
In [316]: m
Out[316]: <__main__.MyType at 0x7f37e70b3ad0>
Even if I use inspect.getsourcelines(m.dynamic_foo)
it's a bit misleading:
In [319]: inspect.getsourcelines(m.dynamic_foo)
Out[319]:
([u' def foo(self, *args, **kwargs):\n',
u" raise ValueError('Invalid coin used to create function.')\n"],
9)
Notice how the function's source shows that its name is "foo" (not "dynamic_foo") and it's not a class method or instance method of MyType
or anything. This is technically correct in the sense that it is the actual lines of source code, but it's not necessarily what someone might expect to see, since it's a definition that exists in a manner disconnected from how it gets dynamically injected into a class definition.
And this is a simple example of this kind of dynamic function creation and dynamic class manipulation. The more complicated this gets, the less reliable it is to count on inspecting source lines as a reasonable way to understand the function's implementation.