我想知道的是 __package__
究竟是什么意思?在官方文档中没有找到任何解释,即使是在SO。
如果你能提供一些例子,我会非常高兴。
答案 0 :(得分:40)
请参阅PEP 366和import system reference documentation:
主要的建议更改是引入新的模块级属性
__package__
。如果存在,相对导入将基于此属性而不是模块__name__
属性。
和
- 应设置模块的
__package__
属性。它的值必须是一个字符串,但它可以是与__name__
相同的值。如果该属性设置为None
或缺少,则导入系统将使用更合适的值填充该属性。当模块是包时,其__package__
值应设置为其__name__
。当模块不是包时,__package__
应设置为顶级模块的空字符串,或子模块的空字符串,设置为父包的名称。有关详细信息,请参阅PEP 366。
因此,对于位于foo/bar/baz.py
的模块,__name__
设置为foo.bar.baz
,__package__
设置为foo.bar
,而foo/bar/__init__.py
} foo.bar
和__name__
属性都将__package__
。
答案 1 :(得分:16)
我想知道的是
__package__
究竟是什么意思
这是启用显式相对导入的机制。
__package__
也就是说,如果模块位于包中,则__package__
设置为包名称以启用显式相对导入。 Specifically:
当模块是包时,其
__package__
值应设置为__name__
。当模块不是包时,应为子模块设置__package__
到父包的名称。
如果模块位于root或top级别,即使用
导入当前模块import current_module
或当顶级模块作为入口点运行时:
$ python -m current_module
然后__package__
是一个空字符串。或者作为documentation says:
当模块不是包时,
__package__
应设置为顶级模块的空字符串......
如果模块/脚本按文件名运行,__package__
is None:
当主模块由其文件名指定时,
__package__
属性将设置为无。
首先,让我们使用Python 3.6创建一个带有嘈杂调试的文件结构:
text = "print(f'{__name__}, __file__: {__file__}, __package__: {repr(__package__)}')"
from pathlib import Path
Path('foo.py').write_text(text)
Path('package').mkdir()
Path('package/__init__.py').write_text(text)
Path('package/__main__.py').write_text(text)
Path('package/bar.py').write_text(text)
# and include a submodule with a relative import:
Path('package/baz.py').write_text(text + '\nfrom . import bar')
现在我们看到作为模块执行的foo.py具有__package__
的空字符串,而由文件名作为入口点执行的脚本具有None
:
$ python -m foo
__main__, __file__: ~\foo.py, __package__: ''
$ python foo.py
__main__, __file__: foo.py, __package__: None
当我们将包作为入口点的模块执行时,其__init__.py
模块运行,然后运行__main__.py
:
$ python -m package
package, __file__: ~\package\__init__.py, __package__: 'package'
__main__, __file__: ~\package\__main__.py, __package__: 'package'
类似地,当我们执行子模块作为入口点的模块时,__init__.py
模块运行,然后运行:
$ python -m package.bar
package, __file__: ~\package\__init__.py, __package__: 'package'
__main__, __file__: ~\package\bar.py, __package__: 'package'
最后,我们看到显式的相对导入,__package__
的完整原因(这里发生在这里)是启用的:
$ python -m package.baz
package, __file__: ~\package\__init__.py, __package__: 'package'
__main__, __file__: ~\package\baz.py, __package__: 'package'
package.bar, __file__: ~\package\bar.py, __package__: 'package'
注意,在输出中,我已将~
替换为父目录。