我是Python的初学者,我对模块对象如何绑定到包的__init__.py
命名空间有疑问。我将用一些代码更清楚地说明这个问题。
假设有一个名为myPkg
的包,包含两个模块:firstMod
和secondMod
:
myPkg
__init__.py
firstMod.py
secondMod.py
文件__init__.py
如下:
def myFun():
from . import firstMod as fm
myFun()
文件firstMod
为空。
文件secondMod
如下:
def myFun():
from . import firstMod as fm
myFun()
现在,在与myPkg
相同的目录中运行Python 2.7.15解释器,并执行以下操作:
>>> import myPkg
>>> dir(myPkg)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'firstMod', 'myFun']
>>> from myPkg import secondMod
>>> dir(secondMod)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'myFun']
>>>
虽然dir(secondMod)
的结果是意料之中的,但dir(myPkg)
的结果(对我来说)却是出乎意料的。似乎,仅对于包的__init__.py
模块,即使模块是从函数中导入的,导入的模块对象的名称也会绑定到全局命名空间。其他模块中不会出现这种情况。
编辑:事实证明,只有在导入包的模块时才会发生这种情况。从myFun
导入外部模块不会导致__init__.py
中的名称绑定。
有人能解释为什么会发生这种情况吗?还有:有没有办法避免这种行为?
编辑
注意,'firstMod'
在__init__.py
的全局命名空间中的存在是一个仅适用于包的属性。
事实上,如果定义两个模块:
zeroMod.py
firstMod.py
在任何包装之外,并用填充zeroMod.py
def myFun():
import firstMod as fm
myFun()
即使firstMod.py
是第一次加载的,解释器也不会将名称'firstMod'
绑定到zeroMod.py
的全局命名空间:
>>> import zeroMod
>>> dir(zeroMod)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'myFun']
>>>
我不明白为什么__init__.py
会出现名称绑定,而zeroMod.py
不会。
运行时:
import myPkg
Python将加载文件myPkg/__init__.py
并执行它
由于这个包包含一个函数调用(myFun()
),它将执行它(第一次导入时只执行一次)。
myFun()
是:
def myFun():
from . import firstMod as fm
同样,此函数导入firstMod
。因此,文件myPkg/firstMod.py
被加载并执行(由于firstMod.py
为空,所以什么也没做)。
在myPkg
导入结束时,您将在模块级别获得以下对象:
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'firstMod', 'myFun']
然后,在同一个Python会话中,如果您运行:
from myPkg import secondMod
Python不会再次加载文件myPkg/__init__.py
,因为模块已经加载。
Python将加载文件myPkg/secondMod.py
并执行它
这个包包含另一个函数调用(myFun()
),它也会执行它。请注意,您使用相同的名称,但名称空间不同,因此两个myFun()
函数不同。
myFun()
也导入firstMod
:
def myFun():
from . import firstMod as fm
firstMod
已经导入,所以您在secondMod
模块中找不到它:
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'myFun']
您应该考虑的事项:
您应该考虑遵循PEP8命名约定。
模块是单例的(即使在极少数情况下您可以重新加载模块),
如果您不想在模块中运行代码,请使用经典的方法:
例如:
if __name__ == "__main__":
myFun()