Питон: импорт суб‑пакет или суб‑модуль


уже используя плоские пакеты, я не ожидал, что проблема, с которой я столкнулся с вложенными пакетами. Вот...

вид каталога

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 56

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

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

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

from module import attribute1

можно сделать

attribute1 = module.attribute1