Поиск (файл / строка) вызова конструктора в Python

1

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

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

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

Теги:
exception
event-handling
stack-trace

4 ответа

1
Лучший ответ
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 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')
  • 0
    Спасибо, но это не работает надежно для классов, когда init перегружен.
  • 0
    Ах хорошо. Не проверял этот случай, но я полагаю, что он может быть изменен, чтобы найти `self 'в f.f_locals и сохранить значение этого тоже ...
1

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

1

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

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

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

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

  • 0
    +1 за упоминание проблем с сохранением ссылок на фреймы. Оригинальное страшное предупреждение изо рта лошади находится здесь: docs.python.org/library/inspect.html#the-interpreter-stack
0

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

  • 0
    Но чтобы создать хеш, мне все еще нужно обработать всю трассировку стека во время вызова конструктора: /

Ещё вопросы

Сообщество Overcoder
Наверх
Меню