Вопрос по python, import, module, package – Python: импорт подпакета или субмодуля

62

Уже использовав плоские пакеты, я не ожидал, что возникнет проблема с вложенными пакетами. Вот & # x2026;

Directory layout
dir
 |
 +-- test.py
 |
 +-- package
      |
      +-- __init__.py
      |
      +-- subpackage
           |
           +-- __init__.py
           |
           +-- module.py
Content of init.py

И то и другоеpackage/__init__.py а такжеpackage/subpackage/__init__.py пусты

Content of module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
Content of test.py (3 versions) Version 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK

Это плохой и небезопасный способ импортировать вещи (импортировать все навалом), но это работает.

Version 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1

Более безопасный способ импортировать элемент за элементом, но он терпит неудачу, Python не хочет этого: происходит сбой с сообщением: «Нет модуля с именем module». Однако & # xA0; & # x2026;

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here

& # X2026; & # xA0, говорит<module 'package.subpackage.module' from '...'>, Так что это модуль, но это не модуль / -P 8-O ... э-э

Version 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK

Этот работает. Таким образом, вы либо вынуждены все время использовать префикс overkill, либо использовать небезопасный способ, как в версии # 1, и Python запрещает использовать безопасный удобный способ? Лучший способ, который является безопасным и позволяет избежать ненужного длинного префикса, является единственным, который Python отклоняет? Это потому что любитimport * или потому что он любит слишком длинные префиксы (что не помогает применять эту практику)?

Извините за грубые слова, но вот уже два дня я пытаюсь обойти это глупое поведение. Если я где-то полностью не ошибаюсь, у меня возникнет ощущение, что что-то действительно сломано в модели пакетов Python и вложенных пакетов.

Заметки

I don't want to rely on sys.path, to avoid global side effects, nor on *.pth files, which are just another way to play with sys.path with the same global effets. For the solution to be clean, it has to be local only. Either Python is able to handle subpackage, either it's not, but it should not require to play with global configuration to be able to handle local stuff. I also tried use imports in package/subpackage/__init__.py, but it solved nothing, it do the same, and complains subpackage is not a known module, while print subpackage says it's a module (weird behavior, again).

Может быть, я совершенно не прав (такой вариант я бы предпочел), но это заставляет меня сильно разочаровываться по поводу Python.

Любой другой известный способ кроме трех я попробовал? Что-то, о чем я не знаю?

(вздох)

-----% & lt; ----- изменить ----- & gt;% -----

Conclusion so far (after people's comments)

В Python нет ничего похожего на настоящий пакет sub & # x2011; все ссылки на пакеты идут только в глобальный словарь, что означает отсутствие локального словаря, что означает, что нет никакого способа управлять ссылкой на локальный пакет.

Вы должны использовать полный префикс или короткий префикс или псевдоним. Как в:

Full prefix version
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Short prefix version (but repeated prefix)
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
Factorized version

Если вы не хотите импортировать сразу несколько объектов одновременно, вы можете:

from package.subpackage.module import attribute1, attribute2
# and etc.

Не в моем первом любимом вкусе (я предпочитаю иметь одно утверждение импорта для каждой импортируемой сущности), но, возможно, я буду предпочитать его лично.

Update (2012-09-14):

Наконец, на практике все в порядке, кроме как с комментарием о макете. Вместо вышеупомянутого я использовал:

from package.subpackage.module import (

    attribute1, 
    attribute2,
    attribute3,
    ...)  # and etc.
Как идут дела, когда пишешь? модуль импорта & quot; в & quot; / package / subpackage / __ init __. py & quot ;? Markus Unterwaditzer
Ваша & quot; факторизованная версия & quot; кажется совершенно правильным для того, что вы хотите сделать. Если вы выполняете отдельную строку импорта для attribute1 и attribute2 (как вы «предпочитаете»), вы просто сознательно даете себе больше работы. Нет причин делать это. BrenBarn
Извините, но я не понимаю, что вы хотите. Не могли бы вы перефразировать ваш вопрос более четко? Что бы вы хотели сделать именно? Я имею в виду, что бы вы хотели написать, что не работает и как вы ожидаете, что это будет работать? Из того, что я прочитал, я думаю, что семантика импорта должна быть похожа на Java или, возможно, на C. Последнее, что вы можете сделать: модуль «star-import». безопасное добавление__all__ переменная, которая содержит список имен, которые должны быть экспортированы при импортировании по звездам. редактировать: хорошо, читая ответ BrenBarn, я понял, что вы имели в виду. Bakuriu

Ваш Ответ

3   ответа
51

Вы, кажется, неправильно понимаете, какimport ищет модули. Когда вы используете оператор импорта этоalways ищет фактический путь к модулю (и / илиsys.modules); он не использует модульobjects в локальном пространстве имен, которые существуют из-за предыдущего импорта. Когда вы делаете:

import package.subpackage.module
from package.subpackage import module
from module import attribute1

Вторая строка ищет пакет с именемpackage.subpackage и импортmodule из этого пакета. Эта строка не влияет на третью строку. Третья строка просто ищет модуль под названиемmodule и не находит его. Он не "повторно использует" объект называетсяmodule что вы получили из строки выше.

Другими словамиfrom someModule import ... "не имеет в виду" из модуля, названного someModule, который я импортировал ранее ... & quot; это означает "из модуля с именем someModule, который вы найдете в sys.path ...". Не существует способа "постепенно" создать путь модуля, импортировав пакеты, которые к нему ведут. При импорте вы всегда должны ссылаться на полное имя модуля.

Неясно, чего вы пытаетесь достичь. Если вы хотите импортировать только конкретный объект attribute1, просто выполнитеfrom package.subpackage.module import attribute1 и покончим с этим. Вам никогда не нужно беспокоиться о долгомpackage.subpackage.module как только вы импортируете нужное имя из него.

если тыdo хотите иметь доступ к модулю для доступа к другим именам позже, тогда вы можете сделатьfrom package.subpackage import module и, как вы уже видели, вы можете сделатьmodule.attribute1 и так далее сколько угодно.

Если ты хочешьboth --- если хочешьattribute1 прямо доступныйand ты хочешь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
Я не уверен, что вы все еще понимаете, как это работает. Или что вы сделали в 2012 году в любом случае.
@ Hibou57: Мне все еще не ясно, чего вы пытаетесь достичь в своей "Версии 2". Что вы хотите сделать, это невозможно? Вы хотите никогда не перепечатывать какую-либо часть имени пакета / модуля / атрибута, но все же импортировать как модуль, так и его атрибут?
Я хотел иметь локальную ссылку на пакет, так же, как вы можете иметь локальную ссылку на объект. Кажется, наконец-то есть действительно локальные ссылки на модули, но вы не можете импортировать их. Это смесь локального и глобального со смешным вкусом (некоторые вещи могут быть локальными, некоторые должны быть глобальными, мне это не нравится, но я в порядке, пока я теперь лучше понимаю, как это работает). Кстати, спасибо за ваше сообщение. Hibou57
Ваши комментарии идут в том же направлении, что и комментарии Игнасио Васкеса-Абрамса (я прокомментировал его сообщение). Вы дополнение в конце, об использованииmodule.attribute1 это то, о чем я думаю, но я думаю, что есть способ избежать необходимости префикса везде. Поэтому я должен либо использовать префикс везде, либо создавать локальный псевдоним, повторяя имя. Не тот стиль, которого я ожидал, но если нет никакого способа (в конце концов, я привык к Аде, которая требует чего-то подобного с ее объявлениями переименования). Hibou57
0

Если все, что вы пытаетесь сделать, это получить attribute1 в вашем глобальном пространстве имен, то версия 3 выглядит просто отлично. Почему префикс излишнего?

В версии 2 вместо

from module import attribute1

ты можешь сделать

attribute1 = module.attribute1
Я думаю, я, как и все люди, комментирующие здесь, не понимаю, что вы хотите делать. Во всех приведенных вами примерах выглядит, что вы хотите получить символ из подпакета в вашем пространстве имен. Ваш нерабочий пример (пример 2) хочет сделать это, импортировав подмодуль из пакета, а затем импортировав символ из этого подмодуля. Я не знаю, почему вы хотите сделать это в два этапа вместо одного. Может быть, объясните больше, каким будет ваше идеальное решение и почему
attribute1 = module.attribute1 просто повторяет имя без добавленной стоимости. Я знаю, что это работает, но мне не нравится этот стиль (что не означает, что мне не нравится ваш ответ). Hibou57
7

Причина № 2 не в том, чтоsys.modules['module'] не существует (процедура импорта имеет свою собственную область и не может видетьmodule местное название), и нетmodule модуль или пакет на диске. Обратите внимание, что вы можете разделить несколько импортированных имен запятыми.

from package.subpackage.module import attribute1, attribute2, attribute3

Также:

from package.subpackage import module
print module.attribute1
Ваша ссылка наsys.modules['name'] что я не знал до сих пор, заставило меня подумать, что это то, чего я боялся (и BrenBarn подтверждает): в Python нет ничего подобного реальным пакетам sub & # x2011 ;.sys.modules, как следует из его названия, является глобальным, и если все ссылки на модули основаны на этом, то нет ничего похожего на локальную ссылку на модуль (может быть, с Python 3.x?). Hibou57
Да, но это модуль & # x201C; module & # x201D; Я не могу импортировать из ;-) Hibou57
Вы все равно не должны импортировать данные из него. Python имеет «реальные подпакеты» это работает просто отлично. Вы, кажется, путаете модули на диске и локальные ссылки. Может быть, взять курс программирования?
Ваше использование & quot; ссылки & quot; тут неоднозначно; первыйimport в # 2 генерирует локальную ссылку наpackage.subpackage.module связан сmodule.

Похожие вопросы