Как отлаживать динамически определенные функции в Python? - PullRequest
4 голосов
/ 05 января 2010

Есть ли способ отладки функции, которая определяется динамически во время выполнения?

Или, по крайней мере, есть простой способ узнать, где производится эта функция?

Обновление, чтобы дать более подробную информацию:

Я использовал inspect модуль:

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'

Здесь inspect показывает, что метод get_thumbnail_url класса photos.models.Image пинакса создается функцией django.utils.functional.curry._curried. Но он все еще не показывает, где создается метод, а именно, где вызывается функция _curried. Эта информация необходима, чтобы узнать, как реализовано get_thumbnail_url.

Я могу поместить pdb в функцию _curried, но тогда она ломается там много раз, потому что это очень часто используемый вызов функции. Мне нужно иметь некоторые отличительные особенности, чтобы использовать условие точки останова.

Обновление о решении:

Спасибо за все предложения. Я нашел решение. Позвольте мне объяснить, как я нашел это. Может быть, это поможет другим людям:

Сначала я искал термин 'get_thumbnail_url' в исходном коде pinax. Безрезультатно. Во-вторых, я искал термин «миниатюра» в исходном коде pinax. Нет полезного результата. Наконец, я искал термин «карри» в исходном коде pinax. Следующее было одним из нескольких результатов:

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 метод производится этим вызовом: curry(self._get_SIZE_url, size=size)).

Но, конечно, это не общий метод решения. Если вы можете поделиться альтернативными способами узнать, где на самом деле создается динамически определенная функция, это было бы очень полезно.

Edit:

Лучшее общее решение написано ниже Джейсоном Орендорффом.

Ответы [ 2 ]

1 голос
/ 06 января 2010

Учитывая функцию f, в CPython вы можете вывести f.func_code.co_filename и f.func_code.co_firstlineno, чтобы получить файл и номер первой строки. Это не поможет, если функция была создана с использованием eval или exec.

В трассировках также содержится информация о файлах и строках.

Если вы import dis, вы можете использовать dis.dis(f) для просмотра байт-кодов CPython; это может быть бесполезно, но может показывать некоторые строки, которые помогут вам найти правильный путь.

Еще одна вещь, на которую стоит обратить внимание - это PDB , отладчик текстового режима Python. После исключения import pdb; pdb.pm() запускает PDB. Это примитивно, но полезно; введите help для получения списка команд. where показывает стек.

РЕДАКТИРОВАТЬ: Вы упоминаете, что это функция карри. Если он был создан с использованием functools.partial, то у него есть атрибут .func, который ссылается на базовую функцию.

РЕДАКТИРОВАТЬ 2: Общий способ будет установить точку останова на im.get_thumbnail_url, а затем немедленно вызвать ее. Ваша точка останова должна ударить сразу же. Затем переходите к нужному коду.

Поскольку функция карри в этом случае была создана с помощью кода, подобного:

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

другой подход заключается в проверке f.func_closure, например:

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

Функция закрывается по трем переменным: кортежу, dict и функции. Очевидно, что именно эта функция нас интересует (но, к сожалению, эти три ячейки соответствуют переменным args, kwargs и _curried_func, которые определены в функции включения curry, но используются замыканием _curried).

>>> f.func_closure[2].cell_contents
<function say at 0xb77d1d84>
>>> import inspect
>>> inspect.getsource(_)
'def say(x):\n    print x\n'
1 голос
/ 05 января 2010

Не уверен, но вы можете получить функцию для распечатки исходного файла и номера строки, которые были определены в модуле проверки:

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

Он печатает:

script.py:2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...