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

StackOverflow https://stackoverflow.com/questions/602846

  •  03-07-2019
  •  | 
  •  

Вопрос

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

фу.py:

def f():
    print __name__

бар.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»), чтобы файлы журналов каждого приложения находились в соответствующих каталогах журналов.

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

Это было полезно?

Решение

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

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

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

Поскольку ответ всегда «да», ваш вопрос неправильно сформулирован.Реальный вопрос: «Как хороший способ, чтобы мой модуль журнала знал имя клиента?» или что-то вроде того.

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

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

logger= logging.getLogger( __name__ )

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

Другие советы

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

import sys
sys.modules[__name__]

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

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

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

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

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

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

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

__file__ — путь к текущему модулю, к которому был сделан вызов.

Чтобы получить ссылку на модуль «__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__

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

С использованием __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».)

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

Если вам нужно только имя файла:

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

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

 import os
 parts = os.path.splitext(__name__)
 module_name = parts[len(parts) - 2]
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top