Питон: импорт суб‑пакет или суб‑модуль
уже используя плоские пакеты, я не ожидал, что проблема, с которой я столкнулся с вложенными пакетами. Вот...
вид каталога
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