Python:从x导入y改变了之前的导入结果

3

我正在尝试理解Python中的包和模块名称屏蔽规则,并偶然发现了一个情况,我不明白为什么看到的结果是有意义的。这种情况发生在Python 2(使用from future import absolute_imports)和Python 3。

假设我有以下文件夹结构:

├── mypackage
│   ├── argparse.py
│   └── __init__.py
└── script.py

mypackage 是我自定义的顶级包,其中我有一个模块覆盖了标准的 argparse 模块。在我的脚本中,我执行以下代码:

import argparse
print(argparse)
from mypackage.argparse import foo
print(argparse)

结果符合我的预期:

<module 'argparse' from '/usr/lib/python3.5/argparse.py'>
<module 'argparse' from '/usr/lib/python3.5/argparse.py'>

然而,如果我改变我的脚本以执行来自我的包的函数,并在我的包的 __init__.py 中执行相同的导入和打印语句,即:

脚本:

from mypackage import main
main()

__init__.py:

import argparse
print(argparse)
from mypackage.argparse import foo
print(argparse)

def main():
    pass

因此,我看到:

<module 'argparse' from '/usr/lib/python3.5/argparse.py'>
<module 'mypackage.argparse' from '/tmp/test/src/mypackage/argparse.py'>

为什么在这种情况下(而不是另一种情况),from X import Y语句会覆盖先前全局导入的argparse到本地模块的导入?
1个回答

1
考虑如何访问子模块,您需要写 mypackage.argparse 来访问 mypackage 的子模块。
现在考虑模块属性查找的方法,它会在模块的全局命名空间中搜索属性。
综合上述两点,访问子模块的唯一方法是将它们添加到包的全局命名空间中,这是预期的行为。

这个有没有在某个地方有记录?我感觉这使得使用绝对导入获得的好处减少了50%。 - languitar
关于包的文档严重缺乏解释__init__.py在许多方面的工作原理。 :/ - Tadhg McDonald-Jensen
好的,谢谢。那么我除了以不寻常的方式安排我的导入来确保在 from X.... 语句之后导入 argparse 之外,没有其他处理方法了吗? - languitar
如果你在包的顶层导入 argparse,那么使用 mypackage.argparse 会非常模糊不清,我建议将其导入为不同的名称(例如 _std_argparse)。 - Tadhg McDonald-Jensen
我曾经因编写多个库而发生过几次冲突,有时像 mypackage.utils.argparse 这样的名称非常清晰明了。 - languitar
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接