Получить __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.foo] Hello

Я хочу, чтобы caller_name был установлен в атрибут __name__ модуля вызывающих функций (который является "myapp.foo" ) в этом случае. Как это можно сделать?

Ответ 1

Проверьте модуль проверки:

inspect.stack() вернет информацию о стеке.

Внутри функции inspect.stack()[1] вернет стек вызывающего абонента. Оттуда вы можете получить дополнительную информацию о имени функции, номере модуля и т.д.

Подробнее см. в документах:

http://docs.python.org/library/inspect.html

Кроме того, у Дуга Хеллмана есть хорошая запись проверяющего модуля в его серии PyMOTW:

http://pymotw.com/2/inspect/index.html#module-inspect

EDIT: Вот какой код, который делает то, что вы хотите, я думаю:

def info(msg):
    frm = inspect.stack()[1]
    mod = inspect.getmodule(frm[0])
    print '[%s] %s' % (mod.__name__, msg)

Ответ 2

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

>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}

Затем вы можете "переместиться вверх" с помощью f_back:

>>> f = 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, как это предложил Марк Родди. Я не уверен в ограничениях и предостережениях этого метода (несколько потоков, скорее всего, будут проблемой), но я намерен использовать его в моем случае.

Ответ 3

Я не рекомендую это делать, но вы можете достичь своей цели следующим способом:

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)