Все, что я хочу знать, , что именно означает __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'
Обратите внимание, что в выводе я заменил ~ на родительские каталоги.