Python 3 中的“from dot import asterisk”有什么作用?

lum*_*ric 5 python python-import python-3.x relative-import

问题

下面这行代码在 Python 3 中起什么作用?

>>> from . import *
Run Code Online (Sandbox Code Playgroud)

到目前为止我发现了什么......

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

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

这可能是警告模块的一部分,表示在某处有一个未打印的警告,但文档仅提到了模块中的一个变量__warningregistry__warnings

该文档解释了如何from . import foo 工作以及如何from bar import * 工作,但我找不到任何有关from . import *. 人们可能期望所有名称都__init__.py加载到当前名称空间中(就像from bla import *一样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
Run Code Online (Sandbox Code Playgroud)

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

Mis*_*agi 4

__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)
Run Code Online (Sandbox Code Playgroud)

这造成了from . import *麻烦,并__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)
Run Code Online (Sandbox Code Playgroud)

添加__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)
Run Code Online (Sandbox Code Playgroud)