2009-04-04 2 views
1

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

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

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

ответ

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'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') 
+0

Спасибо, но это не работает надежно для классов, когда __init__ перегружен. –

+0

А, ладно. Не проверял этот случай, но я полагаю, что он может быть изменен, чтобы найти «я» в f.f_locals и сохранить значение этого тоже ... – AKX

0

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

+0

Но для создания хэша мне все равно нужно обработать весь стек в момент, когда вызывается конструктор:/ –

1

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

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

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

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

+0

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

1

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