Вот файлы в этом тесте:Python: выполнять относительный импорт при использовании __import__?
main.py
app/
|- __init__.py
|- master.py
|- plugin/
|- |- __init__.py
|- |- p1.py
|- |_ p2.py
Идея заключается в том, чтобы иметь плагин с поддержкой приложений. Новые .py или .pyc-файлы можно отбросить в плагины, которые соответствуют моему API.
У меня есть файл master.py
на уровне приложения, который содержит глобальные переменные и функции, к которым может иметь доступ любой плагин, а также само приложение. Для целей этого теста «приложение» состоит из тестовой функции в app/__ init__.py. На практике приложение, вероятно, будет перемещено в отдельный файл (ы) кода, но тогда я бы просто использовал import master
в этом файле кода, чтобы привести ссылку на master
.
Вот содержимое файла:
main.py:
import app
app.test()
app.test2()
приложение/__ init__.py:
import sys, os
from plugin import p1
def test():
print "__init__ in app is executing test"
p1.test()
def test2():
print "__init__ in app is executing test2"
scriptDir = os.path.join (os.path.dirname(os.path.abspath(__file__)), "plugin")
print "The scriptdir is %s" % scriptDir
sys.path.insert(0,scriptDir)
m = __import__("p2", globals(), locals(), [], -1)
m.test()
приложение/master.py:
myVar = 0
app/plugin/__ init__.py:
<empty file>
приложение/плагин/p1.py:
from .. import master
def test():
print "test in p1 is running"
print "from p1: myVar = %d" % master.myVar
приложение/плагин/p2.py:
from .. import master
def test():
master.myVar = 2
print "test in p2 is running"
print "from p2, myVar: %d" % master.myVar
Поскольку я явно импортировать p1
модуль, все работает, как ожидалось. Однако, когда я использую __import__
импортировать p2, я получаю следующее сообщение об ошибке:
__init__ in app is executing test
test in p1 is running
from p1: myVar = 0
__init__ in app is executing test2
The scriptdir is ....../python/test1/app/plugin
Traceback (most recent call last):
File "main.py", line 4, in <module>
app.test2()
File "....../python/test1/app/__init__.py", line 17, in test2
m = __import__("p2", globals(), locals(), [], -1)
File "....../python/test1/app/plugin/p2.py", line 1, in <module>
from .. import master
ValueError: Attempted relative import in non-package
выполнения продолжается весь путь через функцию тест() и ошибку прямо в test2() пытается выполнить свою __import__
заявления, которое в своей очереди, p2 пытается сделать относительный импорт (который делает работы, когда p1 импортируются явно через оператор импорта, напомнит)
Очевидно, что использование __import__
это делать что-то другое, чем при использовании import
заявления. В документах Python указано, что использование импорта просто переводит на заявление __import__
внутри, но должно быть больше, чем кажется на первый взгляд.
Поскольку приложение основано на плагинах, кодирование явных операторов импорта в главном приложении, конечно, нецелесообразно. Использование самого импорта в пределах
Что мне здесь не хватает? Как я могу заставить Python вести себя так, как ожидалось, при ручном импорте модулей с использованием __import__
? Кажется, возможно, я не совсем понимаю идею относительного импорта или что у меня просто отсутствует что-то относительно того, где происходит импорт (т.внутри функции, а не в корне файла кода)
EDIT: Я нашел следующие возможные, но неудачные решения:
m = __import__("p2",globals(),locals(),"plugin")
(возвращает ту же самую точную ошибку, как указано выше)
m = __import__("plugin",fromlist="p2")
(возвращает ссылку на app.plugin, чтобы не app.plugin.p2)
m = __import__("plugin.p2",globals(),locals())
(возвращает повторно Ференц к app.plugin, не app.plugin.p2)
import importlib
m = importlib.import_module("plugin.p2")
(возвращается :)
Traceback (most recent call last):
File "main.py", line 4, in <module>
app.test2()
File "....../python/test1/app/__init__.py", line 20, in test2
m = importlib.import_module("plugin.p2")
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
__import__(name)
ImportError: No module named plugin.p2
Возможный дубликат http://stackoverflow.com/questions/3439082/referring -to-class-names-through-strings – blazetopher
В качестве альтернативы вы можете сделать что-то вроде того, что я предложил в своем ответе на этот вопрос ... по существу получить список файлов в приложении/master/plugin и загрузить их динамически: http://stackoverflow.com/questions/17251008/python-call-a-constructor-whose-name-is-stored-in-a-variable/ – blazetopher
@blazetopher Вы говорите об устранении master.py и просто используете глобальное пространство имен? Как-то это в лучшем случае кажется немного опасным - возможные столкновения имен и т. Д.? – fdmillion