Предположим, у меня есть два модуля:
first.package.module
# Assign module to a variable
which_module = ???
print("I originally live in {}".format(__name__)) # Prints first.package.module
print("I was run from {}".format(which_module))
first.package.module
from first.package.module import *
third.package.module
from first.package.module import *
Как я могу получить вторую строку, «я был запущен», чтобы напечатать second.package.module после импорта в файле second.package.module? Или third.package.module, когда он запускается оттуда.
Причина, по которой я хочу это поведение, связана с созданием приложения в Django, которое используется несколько раз в одном проекте, т. Е. Есть несколько примеров то же приложение. Каждый из этих экземпляров имеет свои собственные модели, которые наследуются от абстрактной модели. Чтобы создавать многократно используемые виды и URL-адреса, я хочу динамически загружать модели, и для этого мне нужно знать, какой модуль импортировал приложение и запускал его.
Вы можете напечатать имя модуля, запускающего загрузку модуля, с помощью:
import sys
print sys._getframe(1).f_globals['__name__']
. В Python 3 с новым стеком importlib вам нужно увеличить кадрэкран до 6 (по крайней мере для 3.5, 3.6 и 3.7):
print(sys._getframe(6).f_globals['__name__'])
Решение кросс-CPython должно отфильтровывать любые importlib._bootstrap* элементы в стеке:
import sys
def imported_from(depth=0):
# skip the frames of this function, and the caller
f = sys._getframe(2 + depth)
while f and f.f_code.co_filename.startswith("<frozen importlib._bootstrap"):
f = f.f_back
return f and f.f_globals['__name__']
print(imported_from())
Выше imported_from() может быть определена в модуле утилиты и импортирована; вызов sys._getframe(2) гарантирует, что исходный контекст является тем, что вызвало вызов imported_from(). Укажите положительное целое число в качестве аргумента depth, чтобы увеличить количество пропущенных кадров. Функция работает на любой версии Python, которая предоставляет функцию sys._getframe(), независимо от того, использует ли она стек importlib.
Обратите внимание, что это:
Опирается на деталь реализации CPython (публикация стека кадров недоступна для других реализаций Python). См. Документацию функции sys._getframe(): деталь реализации CPython: эта функция должна использоваться только для внутренних и специализированных целей. Он не гарантированно существует во всех реализациях Python. В Python 3 это зависит от конкретных деталей реализации стека importlib; текущая разработка может добавлять или удалять вызовы в этом стеке. Например, в Python 3.3, который впервые ввел importlib, правильное количество стека для пропуска равно 9, в 3.4 оно уменьшилось до 7, а 3.5 упало до 6 (число, которое с тех пор стабильно). imported_from() работает вокруг этого, но вводит новое зависящее от реализации предположение: что стековые фреймы, связанные с импортом, можно обнаружить, ища префикс <frozen importlib._bootstrap в имени файла. Теоретически можно скомпилировать CPython с importlib._bootstrap, оставшимся незамерзающим (не включенным в двоичный файл интерпретатора как массив данных marshal). Работает только тогда, когда модуль импортируется в первый раз, после чего Python выполняет код модуля для создания объекта sys.modules.Я не могу подчеркнуть последнюю точку. Python только когда-либо загружает модуль один раз. Импорт - это двухэтапный процесс: загрузка и привязка. Шаг загрузки выполняется только в том случае, если объект модуля еще не существует, все остальные импорты для модуля связывают только имена.
Названия привязок - это не то, что вы можете практически подключить; import modulename - это не более чем назначение modulename = sys.modules['modulename'] после того, как модуль уже находится в памяти.