Ситуация такова: у вас есть сценарий (run.py
), пакет test
и его подмодуль test.b
.
Всякий раз, когда вы импортируете подмодуль в Python, имя этого подмодуля автоматически сохраняется в родительском пакете. Так что, когда вы делаете import collections.abc
(или from collections.abc import Iterable
, или аналогичный), пакет collections
автоматически получает атрибут abc
.
Это то, что происходит здесь. Когда вы делаете:
from b import B
имя b
автоматически загружается в test
, потому что b
является подмодуль test
пакета.
Даже если вы не делаете import b
явно, всякий раз, когда вы импортируете этот модуль, имя помещается в test
. Потому что b
является подмодулем test
и относится к test
.
Боковой узел: ваш код не будет работать с Python 3, потому что relative imports have been removed.Для того, чтобы сделать код работы с Python 3, вы должны написать:
from test.b import B
Этот синтаксис совершенно идентичен from b import B
, но гораздо более явным, и поможет вам понять, что происходит.
Ссылка:Python reference documentation также объясняет такое поведение, и включает в себя полезный пример, очень похожий на эту ситуацию (разница только что используется абсолютный импорт вместо относительного импорта).
Когда подмодуль загружаются с помощью какого-либо механизма (например, importlib
API, то import
или import-from
отчетности, или встроенного в __import__()
) связывание помещаются в пространстве имен родительского модуля к объекту подмодуля. Например, если пакет spam
имеет подмодуль foo
, после импорта spam.foo
, spam
будет иметь атрибут foo
, который привязан к подмодулю.
Допустим, у вас есть следующая структура каталогов:
spam/
__init__.py
foo.py
bar.py
и spam/__init__.py
имеют следующие строки в нем:
from .foo import Foo
from .bar import Bar
затем выполняешь следующее ставит имя связывания foo
и bar
в spam
модуль:
>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.bar
<module 'spam.bar' from '/tmp/imports/spam/bar.py'>
Учитывая знакомые правила привязки имени Python, это может показаться удивительным, но на самом деле это фундаментальная особенность системы импорта. Инвариантный холдинг состоит в том, что если у вас есть sys.modules['spam']
и sys.modules['spam.foo']
(как и после импорта), последний должен отображаться как атрибут foo
первого.
извинения за неправильный ответ ... просто удалили его, чтобы не создавать путаницу. @ Poke спасибо за указание на это ... не заметили изначально то, что вы упомянули. –