Уже имея плоские пакеты, я не ожидал проблемы, с которой я столкнулся с вложенными пакетами. Вот...
Макет каталога
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 этого не хочет: сбой: сообщение "No module named 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... uh
Версия 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.
Какой-либо другой известный способ, помимо трех, которые я пробовал? Что-то, о чем я не знаю?
(Вздох)
-----% < ----- edit ----- > % -----
Заключение до сих пор (после комментариев пользователей)
В Python нет ничего похожего на настоящий подпакет, так как все ссылки на пакеты ссылаются только на глобальную dictionnary, что означает, что нет локального словаря, что означает, что нет способа управлять ссылкой локального пакета.
Вам нужно либо использовать полный префикс, либо короткий префикс или псевдоним. Как в:
Полная префиксная версия
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.