Поскольку я уже использовал плоские пакеты, я не ожидал проблемы, с которой столкнулся с вложенными пакетами. Вот…
Макет каталога
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 этого не хочет: сбой с сообщением: «Нет модуля с именем модуль». Однако …
# 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.