这似乎与解释器如何在模块/子模块级别解析变量赋值的相互作用有关。如果我们使用在我们试图查询的模块之外执行的代码来查询任务,我们可能能够获取更多信息。
在我的例子中,我有以下内容:
代码列表
src/example/package/module.py
:
from logging import getLogger
__all__ = ['fn1']
logger = getLogger(__name__)
def fn1():
logger.warning('running fn1')
return 'fn1'
代码列表
src/example/package/__init__.py
:
def print_module():
print("`module` is assigned with %r" % module)
现在在交互式解释器中执行以下操作:
>>> from example.package import print_module
>>> print_module()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/example.package/src/example/package/__init__.py", line 2, in print_module
print("`module` is assigned with %r" % module)
NameError: name 'module' is not defined
到目前为止,一切都很好,例外情况看起来完全正常。现在让我们看看如果
example.package.module
导入:
>>> import example.package.module
>>> print_module()
`module` is assigned with <module 'example.package.module' from '/tmp/example.package/src/example/package/module.py'>
鉴于相对导入是完整导入的简写语法,让我们看看如果我们修改
__init__.py
包含绝对导入而不是相对导入,就像刚才在交互式解释器中所做的那样,看看现在会发生什么:
import example.package.module
def print_module():
print("`module` is assigned with %r" % module)
再次启动交互式解释器,我们看到:
>>> print_module()
`module` is assigned with <module 'example.package.module' from '/tmp/example.package/src/example/package/module.py'>
请注意
__init__.py
实际上表示模块绑定
example.package
,直觉可能是,如果
example.package.module
导入后,解释器将提供以下赋值
module
到
example.package
协助解决
example.package.module
,无论是绝对进口还是相对进口。这似乎是在执行代码时的一个特殊怪癖
可能有子模块的模块
(即。
__init__.py
).
实际上,还有一个测试。让我们看看变量赋值是否有什么奇怪的地方。修改
src/example.package/__init__.py
致:
import example.package.module
def print_module():
print("`module` is assigned with %r" % module)
def delete_module():
del module
新功能将测试是否
模块
实际上被分配到以下范围
__init__.py
执行此操作后,我们了解到:
>>> from example.package import print_module, delete_module
>>> print_module()
`module` is assigned with <module 'example.package.module' from '/tmp/example.package/src/example/package/module.py'>
>>> delete_module()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/example.package/src/example/package/__init__.py", line 7, in delete_module
del module
UnboundLocalError: local variable 'module' referenced before assignment
事实上,事实并非如此,因此解释器确实在解析引用
模块
通过导入系统,而不是分配给范围内的任何变量
__init__.py
因此,先前的直觉实际上是错误的,但实际上是解释者解决了
模块
名称内
example.package
(即使这是在
__init__.py
)通过模块系统一次
example.package.module
是进口的。
我还没有研究过处理模块和导入的赋值/名称解析的具体PEP,但考虑到这个小练习证明了这个问题不仅仅依赖于相对导入,而且无论何时何地完成导入,赋值都会被触发,因此可能存在一些问题,但这希望能让我们更好地理解Python的导入系统如何处理与导入模块相关的名称解析。