首页 > 解决方案 > 'from dot import asterisk' 在 Python 3 中有什么作用?

问题描述

问题

以下行在 Python 3 中做了什么?

>>> from . import *

到目前为止我发现的...

它不输出任何东西,我在 Python 3.7.3 中看到的唯一变化如下:

>>> '__warningregistry__' in locals()
False
>>> from . import *
>>> '__warningregistry__' in locals()
True
>>> locals()['__warningregistry__']
{'version': 0}

这可能是警告模块的一部分,表示某处存在未打印的警告,但文档仅提及 __warningregistry__模块中的一个变量warnings

该文档解释了如何from . import foo 工作以及如何from bar import * 工作,但我找不到任何关于from . import *. 有人可能期望 from 的所有名称__init__.py都加载到当前名称空间中(就像from bla import *for一样bla.py),但这似乎不是这种情况,而且在__name__ == '__main__'(脚本和终端)时也没有任何意义。

Python 2 的行为与我的预期更相似:

>>> # Python 2.7.16
>>> from . import *
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Attempted relative import in non-package

PEP 328很有启发性,但也没有回答我的问题。

标签: pythonpython-3.xpython-importrelative-import

解决方案


何时__main__是脚本或交互式会话,.__main__包本身:

$ python3 -c 'from . import float'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: cannot import name 'float' from '__main__' (unknown location)

这使得from . import *一个noop,__warningregistry__作为机器的副作用添加import


相对进口来自PEP 366__main__的特殊情况。这引入了相对包名查找,指定具有特殊值。__package____main__. __package__None

此外,模块导入规范__main__.__spec__可能是None- 即在交互式 shell 中或在执行脚本时。

事实证明,任何带有的模块__package__ = __spec__ = None都将.视为它自己:

$ cat test.py
__package__ = __spec__ = None
from . import float
$ python3 -c 'import test'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/mfischer/PycharmProjects/lispy/test.py", line 2, in <module>
    from . import float
ImportError: cannot import name 'float' from 'test' (./test.py)

__warningregistry__添加是因为缺少属性存在隐藏警告。默认情况下它被抑制,但您可以在启用所有警告的情况下看到它:

$ python3 -Wa -c 'from . import float'
-c:1: ImportWarning: can't resolve package from __spec__ or __package__, falling back on __name__ and __path__
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: cannot import name 'float' from '__main__' (unknown location)

推荐阅读