Получить __name__ модуля вызывающей функции в Python
Предполагать myapp/foo.py
содержит:
def info(msg):
caller_name = ????
print '[%s] %s' % (caller_name, msg)
А также myapp/bar.py
содержит:
import foo
foo.info('Hello') # => [myapp.bar] Hello
я хочу caller_name
быть установлен на __name__
атрибут модуля вызывающих функций (в данном случае это myapp.foo). Как это может быть сделано?
4 ответа
Проверьте модуль проверки:
inspect.stack()
вернет информацию о стеке.
Внутри функции, inspect.stack()[1]
вернет стек вашего абонента. Оттуда вы можете получить больше информации об имени функции вызывающего абонента, модуле и т. Д.
Смотрите документы для деталей:
http://docs.python.org/library/inspect.html
Кроме того, у Дуга Хеллманна есть хорошая рецензия на модуль проверки в его серии PyMOTW:
http://pymotw.com/2/inspect/index.html
РЕДАКТИРОВАТЬ: Вот код, который делает то, что вы хотите, я думаю:
def info(msg):
frm = inspect.stack()[1]
mod = inspect.getmodule(frm[0])
print '[%s] %s' % (mod.__name__, msg)
Столкнувшись с подобной проблемой, я обнаружил, что sys._current_frames() из модуля sys содержит интересную информацию, которая может помочь вам, без необходимости импортировать проверку, по крайней мере в определенных случаях использования.
>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}
Затем вы можете "двигаться вверх", используя f_back:
>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(sys._current_frames().values())[0]
>>> print f.f_back.f_globals['__file__']
'/base/data/home/apps/apricot/1.6456165165151/caller.py'
>>> print f.f_back.f_globals['__name__']
'__main__'
Для имени файла вы также можете использовать f.f_back.f_code.co_filename, как это было предложено Марком Родди выше. Я не уверен в ограничениях и предостережениях этого метода (несколько потоков, скорее всего, будут проблемой), но я намерен использовать его в моем случае.
Я не рекомендую делать это, но вы можете достичь своей цели следующим способом:
def caller_name():
frame=inspect.currentframe()
frame=frame.f_back.f_back
code=frame.f_code
return code.co_filename
Затем обновите существующий метод следующим образом:
def info(msg):
caller = caller_name()
print '[%s] %s' % (caller, msg)
Как по мне, следующей строки было достаточно, чтобы узнать имя звонящего.
import inspect
frame = inspect.stack()[-1]
print(frame.filename)