Как я могу получить доступ к текущему исполняющему модулю или имени класса в Python?

Я хотел бы иметь возможность динамически извлекать текущий исполняемый модуль или имя класса из импортированного модуля. Вот какой код:

foo.py:

def f():
    print __name__

bar.py:

from foo import f

def b(): f()

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

Изменить: Модуль inspect выглядит довольно многообещающим, но это не совсем то, что я искал. На что я надеялся, была какая-то глобальная переменная или переменная уровня среды, к которой я мог получить доступ, которая будет содержать имя текущего исполняемого модуля. Не то, чтобы я не хотел пересекать стек, чтобы найти эту информацию - я просто подумал, что Python, возможно, уже разоблачил эти данные.

Изменить: Вот как я пытаюсь это использовать. У меня есть два разных приложения Django, которым необходимо записывать ошибки в файл. Допустим, что они называются "AppOne" и "AppTwo". У меня также есть место, куда я хотел бы записать эти файлы: "/home/hare/app_logs". В каждом приложении в любой заданной точке я хотел бы иметь возможность импортировать мой модуль журнала и вызвать функцию журнала, которая записывает строку журнала в файл. Однако то, что я хотел бы сделать, это создать каталог под app_logs, который является именем текущего приложения ( "AppOne" или "AppTwo" ), чтобы файлы журналов каждого приложения попадали в их соответствующие каталоги протоколирования.

Чтобы сделать это, я подумал, что лучший способ для модуля журнала должен иметь доступ к какой-то глобальной переменной, которая обозначает текущее имя приложения, поскольку оно отвечает за знание местоположения родительского каталога ведения журнала и создание каталог регистрации приложений, если он еще не существует.

Ответ 1

Из комментария - не вопрос.

Мне просто любопытно посмотреть, возможно ли то, что я пытаюсь сделать.

Ответ "возможно ли" всегда "да". Всегда. Если ваш вопрос не касается путешествий во времени, антигравитации или вечного движения.

Так как ответ всегда "да", ваш вопрос плохо сформирован. На самом деле вопрос в том, "как можно, чтобы мой модуль регистрации знал имя клиента?" или что-то типа того.

Ответ: "Примите это как параметр". Не возитесь с проверкой или поиском таинственных глобалов или других уловок.

Просто следуйте шаблону logging.getLogger() и используйте явно именованные регистраторы. Общая идиома заключается в следующем

logger= logging.getLogger( __name__ )

Это прекрасно обрабатывает почти все имена журналов.

Ответ 2

Это должно работать для ссылки на текущий модуль:

import sys
sys.modules[__name__]

Ответ 3

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

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

def f():
    caller = sys._getframe(1)  # Obtain calling frame
    print "Called from module", caller.f_globals['__name__']

[Изменить]: на самом деле использование модуля inspect, как было предложено выше, вероятно, является более чистым способом получение кадра стека. Эквивалентный код:

def f():
    caller = inspect.currentframe().f_back
    print "Called from module", caller.f_globals['__name__']

(sys._getframe документируется как для внутреннего использования - модуль проверки является более надежным API)

Ответ 4

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

Ответ 5

__file__ - это путь текущего модуля, вызываемый.

Ответ 6

Чтобы получить ссылку на модуль "__main__", когда в другом:

import sys
sys.modules['__main__']

Чтобы затем получить путь к файлу модуля, который включает его имя:

sys.modules['__main__'].__file__

Если в модуле "__main__" просто используйте: __file__

Чтобы получить только имя файла из пути к файлу:

import os
os.path.basename(file_path)

Чтобы отделить имя файла от его расширения:

file_name.split(".")[0]

Чтобы получить имя экземпляра класса:

instance.__class__.__name__

Чтобы получить имя класса:

class.__name__

Ответ 7

Я не верю, что это возможно из области foo. foo будет знать только о своей внутренней области, поскольку он может быть вызван множеством других модулей и приложений.

Ответ 8

Использование только __file__ дает вам относительный путь для основного модуля и абсолютный путь для импортированных модулей. Помня об этом, мы можем получить файл модуля постоянно в любом случае с небольшой помощью наших инструментов os.path.

Для имени файла используйте __file__.split(os.path.sep)[-1].

Для полного использования пути os.path.abspath(__file__).

Демо:

/tmp $ cat f.py
from pprint import pprint
import os
import sys

pprint({
    'sys.modules[__name__]': sys.modules[__name__],
    '__file__': __file__,
    '__file__.split(os.path.sep)[-1]': __file__.split(os.path.sep)[-1],
    'os.path.abspath(__file__)': os.path.abspath(__file__),
})

/tmp $ cat i.py
import f

Результаты:

## on *Nix ##

/tmp $ python3 f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': '/tmp/f.py'}

/tmp $ python3 i.py
{'sys.modules[__name__]': <module 'f' from '/tmp/f.pyc'>,
 '__file__': '/tmp/f.pyc',
 '__file__.split(os.path.sep)[-1]': 'f.pyc',
 'os.path.abspath(__file__)': '/tmp/f.pyc'}

## on Windows ##

PS C:\tmp> python3.exe f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

PS C:\tmp> python3.exe i.py
{'sys.modules[__name__]': <module 'f' from 'C:\\tools\\cygwin\\tmp\\f.py'>,
 '__file__': 'C:\\tools\\cygwin\\tmp\\f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

Если вы хотите удалить ".py" с конца, вы можете сделать это легко. (Но не забывайте, что вместо этого вы можете запустить ".pyc".)

Ответ 9

Прошло некоторое время с тех пор, как я сделал python, но я считаю, что вы можете получить доступ к глобальным и локальным пользователям вызывающего абонента через traceback.

Ответ 10

Если вы хотите только имя файла:

file_name = __file__.split("/")[len(__file__.split("/"))-1]

Ответ 11

Чтобы получить текущий файловый модуль, содержащий папку, вот что сработало для меня:

 import os
 parts = os.path.splitext(__name__)
 module_name = parts[len(parts) - 2]