在__init__.py
运行文件时,导入时的行为似乎与导入时的行为不同.
如果我们有以下文件:
run.py
:
import test
test/b.py
:
class B(object): pass
test/__init__.py
:
from b import B print B print b
如果我们运行,__init__.py
我们会得到一个错误:
% python test/__init__.pyTraceback (most recent call last): File "test/__init__.py", line 6, in print b NameError: name 'b' is not defined
但如果我们run.py
这样做,那么我们不会:
% python run.py
我希望这种行为是一样的.为什么这样做?
这只有在我们这样做的情况下才有效__init__.py
.要是我们:
mv __init__.py a.py touch __init__.py
并使run.py
:
import test.a
然后我们得到了错误.
情况如下:你有一个脚本(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,因为相对导入已被删除.要使代码与Python 3一起使用,您必须编写:
from test.b import B
这种语法完全相同from b import B
,但更加明确,应该可以帮助您了解正在发生的事情.
参考:在Python的参考文档也解释了这种行为,并包含一个有用的例子,非常类似于这种情况(所不同的是仅仅是一个绝对导入使用,而不是相对进口).
当使用任何机制(例如
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>>> spam.bar 鉴于Python熟悉的名称绑定规则,这似乎令人惊讶,但它实际上是导入系统的基本功能.不变控股是,如果你有
sys.modules['spam']
和sys.modules['spam.foo']
(可能也会上述进口后),后者必须表现为foo
前者的属性.