Я столкнулся с проблемой наличия импорта в __init__.py
и использования import as
с абсолютным импортом в модулях пакета.
В моем проекте есть подпакет, и в нем __init__.py
я "поднимаю" один из классов из модуля на уровень подпакета с помощью оператора from import as
. Модуль импортирует другие модули из этого подпакета с абсолютным импортом. Я получаю эту ошибку AttributeError: 'module' object has no attribute 'subpkg'
.
пример
Структура:
pkg/
├── __init__.py
├── subpkg
│ ├── __init__.py
│ ├── one.py
│ └── two_longname.py
└── tst.py
pkg/__ init__.py пуст.
pkg/subpkg/__ init__.py:
from pkg.subpkg.one import One
pkg/subpkg/one.py:
import pkg.subpkg.two_longname as two
class One(two.Two):
pass
pkg/subpkg/two_longname.py:
class Two:
pass
pkg/tst.py:
from pkg.subpkg import One
print(One)
Выход:
$ python3.4 -m pkg.tst
Traceback (most recent call last):
File "/usr/lib/python3.4/runpy.py", line 170, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib/python3.4/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/home/and/dev/test/python/imptest2/pkg/tst.py", line 1, in <module>
from pkg.subpkg import One
File "/home/and/dev/test/python/imptest2/pkg/subpkg/__init__.py", line 1, in <module>
from pkg.subpkg.one import One
File "/home/and/dev/test/python/imptest2/pkg/subpkg/one.py", line 1, in <module>
import pkg.subpkg.two_longname as two
AttributeError: 'module' object has no attribute 'subpkg'
обходные
Есть изменения, которые заставляют это работать:
-
pkg/subpkg/__init__.py
и импортируйте напрямую изpkg.subpkg.one
.Я не рассматриваю это как вариант, потому что AFAIK "поднимает" вещи на уровень пакета в порядке. Вот цитата из статьи:
В
__init__.py
обычно нужно импортировать выбранные классы, функции и т.д. На уровень пакета, чтобы их можно было легко импортировать из пакета. -
Изменение
import as
поone.py
from import
вone.py
:from pkg.subpkg import two_longname class One(two_longname.Two): pass
Единственный минус в том, что я не могу создать короткий псевдоним для модуля. Я понял эту идею из ответа @begueradj.
Также можно использовать относительный импорт в one.py
для решения проблемы. Но я думаю, что это всего лишь вариант обходного пути № 2.
Вопросы
-
Может кто-нибудь объяснить, что на самом деле здесь происходит? Почему сочетание импорта в
__init__.py
и использованияimport as
приводит к таким проблемам? -
Есть ли лучшие обходные пути?
Оригинальный пример
Это мой оригинальный пример. Это не очень реалистично, но я не удаляю его, поэтому ответ @begueradj все еще имеет смысл.
pkg/__ init__.py пуст.
pkg/subpkg/__ init__.py:
from pkg.subpkg.one import ONE
pkg/subpkg/one.py:
import pkg.subpkg.two
ONE = pkg.subpkg.two.TWO
pkg/subpkg/two.py:
TWO = 2
pkg/tst.py:
from pkg.subpkg import ONE
Выход:
$ python3.4 -m pkg.tst
Traceback (most recent call last):
File "/usr/lib/python3.4/runpy.py", line 170, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib/python3.4/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/home/and/dev/test/python/imptest/pkg/tst.py", line 1, in <module>
from pkg.subpkg import ONE
File "/home/and/dev/test/python/imptest/pkg/subpkg/__init__.py", line 2, in <module>
from pkg.subpkg.one import ONE
File "/home/and/dev/test/python/imptest/pkg/subpkg/one.py", line 6, in <module>
ONE = pkg.subpkg.two.TWO
AttributeError: 'module' object has no attribute 'subpkg'
Первоначально у меня было это в one.py:
import pkg.subpkg.two as two
ONE = two.TWO
В этом случае я получаю ошибку при импорте (как и в моем первоначальном проекте, который тоже использует import as
).