简体   繁体   中英

How to debug dynamically defined functions in Python?

Is there a way to debug a function that is defined dynamically in run time?

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

Update to give more detail:

I used 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 photos.models.Image class of pinax is produced by django.utils.functional.curry._curried function. But it still doesn't show where the method is produced, namely where is _curried function called. This information is necessary to find out how get_thumbnail_url is implemented.

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

Update about solution:

Thanks for all suggestions. I found out the solution. Let me explain how I found it. Maybe it will help other people:

First, I searched for 'get_thumbnail_url' term in pinax source code. No result. Second, I searched for 'thumbnail' term in pinax source code. No useful result. Lastly, I searched for 'curry' term in pinax source code. The following 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 method is produced by this call: 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 a dynamically defined function is actually produced, this would be of great use.

Edit:

The best general solution is written below by Jason Orendorff.

Not sure, but you can get a function to print out the source file and line number it was defined in using the inspect module:

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

It prints:

script.py:2

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

Tracebacks contain file and line information too.

If you import dis you can use dis.dis(f) to see the CPython bytecodes; this might not be useful, but it might show some strings that help you find your way to the right place.

Another thing to look at is PDB , the Python text-mode debugger. After an exception, import pdb; pdb.pm() import pdb; pdb.pm() launches PDB. It's primitive, but useful; type help for a list of commands. where shows the stack.

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

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

Since the curried function was, in this case, produced by 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 examine f.func_closure , like this:

>>> 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>)

The function closes on three variables: a tuple, a dict, and a function. Obviously the function is the one we're interested in (but fyi these three cells correspond to the variables args , kwargs , and _curried_func that are defined in the enclosing function curry but used by the closure _curried ).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM