从__init__.py中的函数导入模块是否将模块对象绑定到全局命名空间?

2024-06-02 06:17:31 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python的初学者,我对模块对象如何绑定到包的__init__.py命名空间有疑问。 我将用一些代码更清楚地说明这个问题。你知道吗


假设有一个名为myPkg的包,包含两个模块:firstModsecondMod

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模块,导入的模块对象的名称就绑定到全局名称空间,即使模块是从函数中导入的。这在其他模块中不会发生。你知道吗

Edit:事实证明,只有在导入包的模块时才会发生这种情况。从myFun导入外部模块不会导致__init__.py中的名称绑定。你知道吗


有人能解释为什么会这样吗? 还有:有没有办法避免这种行为?你知道吗


编辑

请注意,'firstMod'__init__.py的全局命名空间中的存在是一个仅适用于包的属性。你知道吗

事实上,如果一个定义了两个模块:

zeroMod.py
firstMod.py

在任何包的外部,并用zeroMod.py填充:

def myFun():
    import firstMod as fm

myFun()

解释器不会将名称'firstMod'绑定到zeroMod.py的全局命名空间,即使firstMod.py是第一次加载的:

>>> import zeroMod
>>> dir(zeroMod)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'myFun']
>>>

我不明白为什么名称绑定发生在__init__.py而不是zeroMod.py。你知道吗


Tags: 模块文件pyimport名称initdefdir
1条回答
网友
1楼 · 发布于 2024-06-02 06:17:31

跑步时:

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 naming conventions

  • 模块是单例的(即使在某些罕见的情况下您可以重新加载模块),

  • 如果不想在模块中运行代码,请使用经典方法:

例如:

if __name__ == "__main__":
    myFun()

相关问题 更多 >