Поиск (файл / строка) вызова конструктора в Python - PullRequest
1 голос
/ 04 апреля 2009

Я внедряю систему событий: различные фрагменты кода будут публиковать события в центральном месте, где они будут распространяться среди всех слушателей. Основная проблема этого подхода: когда во время обработки события возникает исключение, я не могу больше сказать, кто опубликовал событие.

Итак, мой вопрос: есть ли эффективный способ выяснить, кто вызвал конструктор и запомнить это в Python 2.5?

Дополнительная информация. Простой способ - использовать модуль traceback, чтобы получить копию стека в конструкторе и запомнить это. Увы, мне эта информация нужна только редко, поэтому мне интересно, был ли способ кешировать это или я мог просто вспомнить самый верхний кадр стека и вернуться назад в редком случае, когда мне действительно нужны эти данные. *

Ответы [ 4 ]

1 голос
/ 05 апреля 2009

Я думаю, что самый простой метод будет состоять в том, чтобы добавить поле идентификатора к рассматриваемому (ым) событию (ям) и иметь каждый источник события (по любому определению «источника события») здесь) предоставить уникальный идентификатор, когда он публикует событие. Вы получаете немного больше накладных расходов, но, вероятно, этого недостаточно, чтобы быть проблематичным, и я подозреваю, что вы найдете другие способы, которые помогут вам узнать источник события.

1 голос
/ 04 апреля 2009
import sys
def get_caller(ext=False):
    """ Get the caller of the caller of this function. If the optional ext parameter is given, returns the line's text as well. """
    f=sys._getframe(2)
    s=(f.f_code.co_filename, f.f_lineno)
    del f
    if ext:
        import linecache
        s=(s[0], s[1], linecache.getline(s[0], s[1]))

    return s

def post_event(e):
    caller=get_caller(True)
    print "Event %r posted from %r"%(e, caller)

## Testing the functions.

def q():
    post_event("baz")

post_event("foo")
print "Hello!"
q()

результат в

Event 'foo' posted from ('getcaller.py', 20, 'post_event("foo")\n')
Hello!
Event 'baz' posted from ('getcaller.py', 17, '\tpost_event("baz")\n')
1 голос
/ 04 апреля 2009

Вы можете просто сохранить ссылку на объект фрейма вызывающего, но это, вероятно, плохая идея. Это поддерживает живые кадры, а также содержит ссылки на все используемые локальные переменные, поэтому может повлиять на производительность, если они используют большие куски памяти, и может иметь еще худшие последствия, если они полагаются (неправильно) на завершение для уничтожать ресурсы, такие как блокировки и файловые дескрипторы, когда они выходят из области видимости.

Это означает, что вам нужно вместо этого хранить строковое представление трассировки стека, что не идеально подходит для ваших целей (на самом деле нужно выполнить некоторую обработку, чтобы получить его, даже если это редко требуется). К сожалению, кажется, что нет большого пути обойти это, хотя вы можете отключить его, пока не установите какой-либо параметр конфигурации. Таким образом, вы получите лучшую производительность для общего случая, но при этом сможете включить настройку при попытке диагностики сбоев.

Если вашей вызывающей функции (или небольшого числа родительских вызывающих абонентов) достаточно, чтобы различить маршрут (т. Е. Трассировка всегда одинакова при вызове через func1 (), и нет func2 -> func1 () против func3 () -> func1 () для различения), вы можете поддерживать хэш на основе имени файла и номера строки вызывающего кадра (или двух последних вызывающих кадров и т. д.). Однако это, вероятно, не соответствует вашей ситуации, и там, где это не так, вы получите поддельные следы стека.

Обратите внимание, что если вам нужен кадр вызывающего абонента, возможно, лучше использовать inspect.currentframe(depth).

0 голосов
/ 04 апреля 2009

Может быть стоит присоединить хеш трассировки стека к конструктору вашего события и сохранить фактическое содержимое в memcache с хешем в качестве ключа.

...