简体   繁体   English

Python中“__package__”属性的目的是什么?

[英]What's the purpose of the “__package__” attribute in Python?

All I want to know is what exactly does __package__ mean ? 我想知道的是__package__究竟什么意思 Didn't find any explanation in the official doc, even on SO. 在官方文件中没有找到任何解释,即使是在SO上。

If you could provide some examples I would be very happy. 如果你能提供一些例子,我会非常高兴。

See the PEP 366 and import system reference documentation : 请参阅PEP 366导入系统参考文档

The major proposed change is the introduction of a new module level attribute, __package__ . 主要的建议更改是引入新的模块级属性__package__ When it is present, relative imports will be based on this attribute rather than the module __name__ attribute. 如果存在,相对导入将基于此属性而不是模块__name__属性。

and

  • The module's __package__ attribute should be set. 应该设置模块的__package__属性。 Its value must be a string, but it can be the same value as its __name__ . 它的值必须是一个字符串,但它可以是与__name__相同的值。 If the attribute is set to None or is missing, the import system will fill it in with a more appropriate value. 如果该属性设置为“ None或缺少,则导入系统将使用更合适的值填充该属性。 When the module is a package, its __package__ value should be set to its __name__ . 当模块是包时,其__package__值应设置为__name__ When the module is not a package, __package__ should be set to the empty string for top-level modules, or for submodules, to the parent package's name. 当模块不是包时, __package__设置为顶级模块的空字符串,或子模块的空字符串,设置为父包的名称。 See PEP 366 for further details. 有关详细信息,请参阅PEP 366

So, for a module located in foo/bar/baz.py , __name__ is set to foo.bar.baz , and __package__ is set to foo.bar , while foo/bar/__init__.py will have foo.bar for both the __name__ and __package__ attributes. 因此,对于位于模块foo/bar/baz.py__name__设为foo.bar.baz ,并__package__设置为foo.bar ,而foo/bar/__init__.py将有foo.bar同时为__name____package__属性。

All I want to know is what exactly does __package__ mean 我想知道的是__package__究竟是什么意思

It is the mechanism that enables explicit relative imports. 它是实现显式相对导入的机制。

There are three possible categories of values for __package__ __package__有三种可能的值类别

  • A package name (a string) 包名(字符串)
  • An empty string 一个空字符串
  • None 没有

Package Name 包裹名字

That is, if a module is in a package, __package__ is set to the package name to enable explicit relative imports. 也就是说,如果模块位于包中,则__package__将设置为包名称以启用显式相对导入。 Specifically: 特别:

When the module is a package, its __package__ value should be set to its __name__ . 当模块是包时,其__package__值应设置为__name__ When the module is not a package, __package__ should be set [...] for submodules, to the parent package's name. 当模块不是包时,应将子模块的__package__设置为父包的名称。

Empty String 空字符串

If a module is at root, or top-level, that is, the current module is imported with 如果模块位于root或top级别,即导入当前模块

import current_module

or when a top-level module is run as the entry point as with: 或者当顶级模块作为入口点运行时,如下所示:

$ python -m current_module

then __package__ is an empty string. 那么__package__是一个空字符串。 Or as the documentation says : 或者正如文档所说

When the module is not a package, __package__ should be set to the empty string for top-level modules... 当模块不是包时, __package__应该设置为顶级模块的空字符串...

None 没有

If a module/script is run by filename, __package__ is None : 如果模块/脚本由filename运行, __package__为None

When the main module is specified by its filename, then the __package__ attribute will be set to None. 当主模块由其文件名指定时, __package__属性将设置为None。

Evidence 证据

First, let's create a file structure with noisy debugging - using Python 3.6: 首先,让我们使用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')

Now we see that foo.py executed as a module has an empty string for __package__ , while the script executed by file name as the entry point has None : 现在我们看到作为模块执行的foo.py具有__package__的空字符串,而由文件名作为入口点执行的脚本具有None

$ python -m foo
__main__, __file__: ~\foo.py, __package__: ''
$ python foo.py
__main__, __file__: foo.py, __package__: None

When we execute a package as a module for the entry point, its __init__.py module runs, then its __main__.py runs: 当我们执行一个包作为入口点的模块时,它的__init__.py模块运行,然后它的__main__.py运行:

$ python -m package
package, __file__: ~\package\__init__.py, __package__: 'package'
__main__, __file__: ~\package\__main__.py, __package__: 'package'

Similarly, when we execute a submodule as a module for the entry point, the __init__.py module runs, then it runs: 类似地,当我们执行子模块作为入口点的模块时,运行__init__.py模块,然后运行:

$ python -m package.bar
package, __file__: ~\package\__init__.py, __package__: 'package'
__main__, __file__: ~\package\bar.py, __package__: 'package'

Finally, we see that the explicit relative import, the entire reason for having __package__ , (which happens last here) is enabled: 最后,我们看到显式相对导入,具有__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'

Note, in the output, I have substituted ~ for the parent directories. 注意,在输出中,我已经用~替换了父目录。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM