Питон: импорт суб‑пакет или суб‑модуль
уже используя плоские пакеты, я не ожидал, что проблема, с которой я столкнулся с вложенными пакетами. Вот...
вид каталога
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
содержаниеinit. py
и package/__init__.py и package/subpackage/__init__.py пустые.
контент module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
контент test.py (3 версии)
Вариант 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK
это плохой и небезопасный способ ввоза вещей (импорт все навалом), но это работает.
Вариант 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
более безопасный способ импорта, элемент за элементом, но он терпит неудачу, Python не хочет этого: сбой с сообщением: "нет модуля с именем module". Однако ...
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
... говорит <module 'package.subpackage.module' from '...'>. Так что это модуль, но это не модуль /-P 8-O ... ух
Вариант 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
это работает. Таким образом, вы либо вынуждены использовать префикс overkill все время, либо использовать небезопасный способ как и в версии #1 и запрещено Python использовать безопасный удобный способ? Лучший способ, который безопасен и избегает ненужного длинного префикса, - это единственный, который отвергает Python? Это потому, что он любит import * или потому, что он любит слишком длинные префиксы (что не помогает применять эту практику)?.
извините за жесткие слова, но вот уже два дня я пытаюсь обойти это глупое поведение. Если я не был совершенно неправ где-то, это оставит меня с чувством, что что-то действительно разбитые в модели Python или пакет и суб‑пакетов.
Примечания
- я не хочу полагаться на
sys.path, чтобы избежать глобальных побочных эффектов, ни на*.pthфайлы, просто еще один способ играть сsys.pathС теми же глобальными эффектами. Чтобы раствор был чистым, он должен быть только локальным. Либо Python способен обрабатывать подпакет, либо нет, но он не должен требовать, чтобы играть с глобальной конфигурацией, чтобы иметь возможность обрабатывать локальные материал. - я также пытался использовать импорт в
package/subpackage/__init__.py, но он ничего не решил, он делает то же самое, и жалуетсяsubpackageне является известным модулем, в то время какprint subpackageговорит, что это модуль (странное поведение, опять же).
может быть, я совершенно не прав (вариант, который я бы предпочел), но это заставляет меня чувствовать себя очень разочарованным в Python.
любой другой известный способ, кроме трех, которые я пробовал? Что-то, чего я не знаю о чем?
(вздох)
----- %% -----
вывод до сих пор (после комментариев людей)
в Python нет ничего похожего на реальный подпакет, так как все ссылки на пакеты относятся только к глобальному словарю, что означает, что нет локального словаря, что означает, что нет способа управлять локальной ссылкой на пакет.
вы должны либо использовать полный префикс или короткий префикс или псевдоним. Как в:
Полная версия префикса
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
короткая версия префикса (но повторяющийся префикс)
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place
или еще вариант выше.
from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context
Факторизуемая версия
если вы не возражаете против импорта нескольких объектов сразу в пакетном режиме, вы можете:
from package.subpackage.module import attribute1, attribute2
# and etc.
не в моем первом любимом вкусе (я предпочитаю иметь один оператор импорта на импортируемый объект), но может быть тот, который я лично польза.
обновление (2012-09-14):
наконец, кажется, все в порядке на практике, за исключением комментария о макете. Вместо вышесказанного я использовал:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.
3 ответа:
вы, кажется, не понимаете, как
importищет модулей. Когда вы используете оператор импорта это всегда поиск фактического пути модуля (и / илиsys.modules); он не использует модуль объекты в локальном пространстве имен, которое существует из-за предыдущего импорта. Когда вы это сделаете:import package.subpackage.module from package.subpackage import module from module import attribute1вторая строка ищет пакет по имени
package.subpackageи импортаmoduleиз этого пакета. Эта строка не влияет на третью строку. Этот третья строка просто ищет модуль под названиемmoduleи не находит ни одного. Он не "повторно использовать" объект под названиемmoduleчто вы получили из предыдущей строки.другими словами
from someModule import ...не означает " из модуля под названием someModule, который я импортировал ранее..."это означает" из модуля с именем someModule, который вы найдете в sys.путь...". Нет никакого способа "постепенно" построить путь модуля, импортируя пакеты, которые приводят к нему. Вы всегда должны ссылаться на весь модуль имя при импорте.неясно, чего вы пытаетесь достичь. Если вы хотите импортировать только определенный объект attribute1, просто сделайте
from package.subpackage.module import attribute1и покончим с этим. Вам никогда не нужно беспокоиться о длинномpackage.subpackage.moduleпосле того как вы импортировали имя, которое вы хотите от него.если вы do хотите иметь доступ к модулю, чтобы получить доступ к другим именам позже, то вы можете сделать
from package.subpackage import moduleи, как вы видели, вы можете сделатьmodule.attribute1и так далее столько, сколько вы как.если вы хотите и --- то есть, если вы хотите
attribute1напрямую работает и вы хотитеmoduleдоступно, просто сделайте оба из вышеперечисленного:from package.subpackage import module from package.subpackage.module import attribute1 attribute1 # works module.someOtherAttribute # also worksЕсли вам не нравится пишите
package.subpackageдаже дважды, вы можете просто вручную создать локальную ссылку на attribute1:from package.subpackage import module attribute1 = module.attribute1 attribute1 # works module.someOtherAttribute #also works
Причина № 2 терпит неудачу, потому что
sys.modules['module']не существует (процедура импорта имеет свою собственную область и не может видетьmoduleместное имя), и нетmoduleмодуль или пакет на диск. Обратите внимание, что несколько импортированных имен можно разделить запятыми.from package.subpackage.module import attribute1, attribute2, attribute3также:
from package.subpackage import module print module.attribute1