为何`from . import re`初始失败,执行`import re`后成功?(Python 3.7)
Python相对导入的诡异行为:3.7与3.8的差异解析
测试结果对比
Python 3.7.3(Debian 10.12)
$ python3 >>> from . import re Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: cannot import name 're' from '__main__' (unknown location) >>> import re >>> re <module 're' from '/usr/lib/python3.7/re.py'> >>> from . import re >>> re <module 're' from '/usr/lib/python3.7/re.py'>
首次执行相对导入失败,但导入re后再次执行却成功,这明显不符合预期。
Python 3.8.2(macOS 13.2)
>>> from . import re Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: attempted relative import with no known parent package >>> import re >>> re <module 're' from '/Library/Developer/CommandLineTools/Library/Frameworks/ Python3.framework/Versions/3.8/lib/python3.8/re.py'> >>> from . import re Traceback (most recent call last): File "<stdin>", line 1, in <module> ImportError: attempted relative import with no known parent package >>> re <module 're' from '/Library/Developer/CommandLineTools/Library/Frameworks/ Python3.framework/Versions/3.8/lib/python3.8/re.py'>
这里无论是否提前导入re,相对导入都失败,提示没有已知父包。
底层机制与差异原因
相对导入的核心前提:相对导入依赖模块的
__package__属性,只有当模块属于某个包时,该属性才会被正确设置,相对导入才能生效。交互式环境的主模块(__main__)默认没有有效__package__,所以正常情况下相对导入必然失败。Python 3.7的bug:当你导入
re这类顶级模块后,Python 3.7会将主模块的__package__隐式设为空字符串""。此时from . import re会被解释为从“当前包的父级(即顶级命名空间)”导入re——而re已经在顶级命名空间存在,所以操作等价于import re,因此成功。这是违反相对导入设计逻辑的漏洞。Python 3.8的修复:3.8版本严格规范了
__package__的处理逻辑,即使导入了顶级模块,主模块的__package__仍不会被设置为有效包名,因此所有相对导入都会直接抛出错误,这才是符合规范的行为。
总结
你在Python 3.7中看到的异常现象是解释器的bug导致的,Python 3.8及后续版本修复了这个问题,确保相对导入只能在包内部模块中使用,交互式主模块不允许执行相对导入。
内容的提问来源于stack exchange,提问作者pynexj
相关产品推荐
相关产品推荐

