How to debug dynamically defined functions in Python?

Is there a way to debug a function that is dynamically determined at runtime?

Or at least is there an easy way to find out where this function is created?

Refresh to get more details:

I used the inspect module:

 ipdb> inspect.getmodule(im.get_thumbnail_url) Out[0]: <module 'django.utils.functional' from 'C:\java\python\Python25\Lib\site -packages\django\utils\functional.pyc'> ipdb> inspect.getsource(im.get_thumbnail_url) Out[0]: ' def _curried(*moreargs, **morekwargs):\n return _curried_fun c(*(args+moreargs), **dict(kwargs, **morekwargs))\n' 

Here inspect shows that the get_thumbnail_url method of the get_thumbnail_url class for pinax is created by the django.utils.functional.curry._curried function. But it still does not show where the method is created, namely, where the _curried function is _curried . This information is needed to find out how get_thumbnail_url is implemented.

I can put pdb inside _curried , but then it breaks many times because it is a very often used function call. I need to have some distinguishing feature to use a breakpoint condition.

Solution Update:

Thanks for all the suggestions. I have found a solution. Let me explain how I found this. Maybe this will help other people:

First I searched for the term 'get_thumbnail_url' in the pinax source code. To no avail. Secondly, I searched for the term "thumbnail" in the pinax source code. There is no useful result. Finally, I searched for the term "curry" in the pinax source code. Below was one of several results:

 def add_accessor_methods(self, *args, **kwargs): for size in PhotoSizeCache().sizes.keys(): setattr(self, 'get_%s_size' % size, curry(self._get_SIZE_size, size=size)) setattr(self, 'get_%s_photosize' % size, curry(self._get_SIZE_photosize, size=size)) setattr(self, 'get_%s_url' % size, curry(self._get_SIZE_url, size=size)) setattr(self, 'get_%s_filename' % size, curry(self._get_SIZE_filename, size=size)) 

get_thumbnail_url this call is made: curry(self._get_SIZE_url, size=size)) .

But of course, this is not a general solution method. If you can share alternative ways to find out where the dynamically defined function is actually created, this will be very helpful.

Edit:

The best overall solution is written below by Jason Orendorf.

+4
source share
2 answers

For function f in CPython, you can print f.func_code.co_filename and f.func_code.co_firstlineno to get the file number and first line. This will not help if the function was created using eval or exec .

Tracebacks also contains file and line information.

If you are import dis , you can use dis.dis(f) to view CPython bytecodes; this may not be useful, but a few lines may appear to help you find the path you need.

Another thing to look out for is PDB , the Python text mode debugger. After the exception, import pdb; pdb.pm() import pdb; pdb.pm() starts the PDB. It is primitive but useful; enter help list of commands. where shows the stack.

EDIT: You mentioned that this is a curry function. If it was created using functools.partial , then it has an .func attribute that refers to the underlying function.

EDIT 2:. The general way is to set a breakpoint on im.get_thumbnail_url and then call it immediately. Your breakpoint should hit right away. Then take a step until you reach the code you are interested in.

Since in this case the curried function was produced using code like:

 def curry(_curried_func, *args, **kwargs): def _curried(*moreargs, **morekwargs): return _curried_func(*(args+moreargs), **dict(kwargs, **morekwargs)) return _curried 

another approach is to study f.func_closure , for example:

 >>> f <function _curried at 0xb77d64fc> >>> f.func_closure (<cell at 0xb77eb44c: tuple object at 0xb77dfa0c>, <cell at 0xb77eb5e4: dict object at 0xb77d93e4>, <cell at 0xb77eb5cc: function object at 0xb77d1d84>) 

A function is closed by three variables: a tuple, a dict, and a function. Obviously, the function interests us (but these three cells correspond to the variables args , kwargs and _curried_func , which are defined in the attached curry function, but are used by the _curried closure).

 >>> f.func_closure[2].cell_contents <function say at 0xb77d1d84> >>> import inspect >>> inspect.getsource(_) 'def say(x):\n print x\n' 
+1
source

Not sure, but you can get a function to print the source file and the line number that was determined using the validation module:

 import inspect f = lambda: inspect.currentframe().f_code.co_filename + ':' + \ str(inspect.currentframe().f_lineno); print f() 

He prints:

 script.py:2 
+1
source

All Articles