Все, что я хочу знать, , что именно означает __package__
? Не нашел никаких объяснений в официальном документе, даже на SO.
Если бы вы могли привести несколько примеров, я был бы очень доволен.
Все, что я хочу знать, , что именно означает __package__
? Не нашел никаких объяснений в официальном документе, даже на SO.
Если бы вы могли привести несколько примеров, я был бы очень доволен.
См. PEP 366 и справочная документация по системе импорта
Основное предлагаемое изменение - введение нового атрибута уровня модуля,
__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__
.
Все, что я хочу знать, это то, что именно означает
__package__
Это механизм, который разрешает явный относительный импорт.
Существует три возможных категории значений для __package__
То есть, если модуль находится в пакете, для __package__
задается имя пакета, чтобы разрешить явный относительный импорт. частности:
Когда модуль представляет собой пакет, его значение
__package__
должно быть установлено равным__name__
. Если модуль не является пакетом, для субмодулей__package__
следует установить [...] имя родительского пакета.
Если модуль находится в корневом или верхнем уровне, то есть текущий модуль импортируется с помощью
import current_module
или когда модуль верхнего уровня запускается как точка входа, например:
$ python -m current_module
затем __package__
- пустая строка. Или, как сказано в документации:
Когда модуль не является пакетом, для модулей верхнего уровня
__package__
следует установить пустую строку...
Если модуль/скрипт запускается по имени файла, __package__
- Нет:
Если основной модуль указан в имени файла, для атрибута
__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'
Обратите внимание, что в выводе я заменил ~
на родительские каталоги.