Namespace пакеты в Python

Содержание
Введение
Поиск Namespace пакетов
Executable Directories
Executable Zip Files
Executable Packages
Похожие статьи

Введение

Перед изучением этой статьи убедитесь, что вам знакома тема sys.path в Python

PEP 420

Namespace пакеты это механизм, с помощью которого один Python пакет разбивается по различным директориям на диске.

Так как директорий в корых находится namespace пакет несколько, не существует какого-то единого __init__.py файла. Поэтому __init__.py файла вообще может не быть.

При импорте namespace пакета никакой код не будет выполнен по умолчанию.

Поиск Namespace пакетов

Рассмотрим структуру обычного пакета из статьи Пакеты в Python

demo_reader ├── compressed │ ├── bzipped.py │ ├── gzipped.py │ └── __init__.py ├── __init__.py ├── multireader.py └── util ├── __init__.py └── writer.py

Раскидаем этот пакет по двум директориям

project ├── path1 │ └── demo_reader │ ├── multireader.py │ └── util │ ├── __init__.py │ └── writer.py └── path2 └── demo_reader └── compressed ├── bzipped.py ├── gzipped.py └── __init__.py

>>> import sys >>> sys.path.extend(['./path1', './path2']) >>> import demo_reader >>> demo_reader.__path__

_NamespacePath(['/home/andrei/python/./path1/demo_reader', '/home/andrei/python/./path2/demo_reader'])

>>> import demo_reader.util >>> import demo_reader.compressed >>> demo_reader.util.__path__

['/home/andrei/python/./path1/demo_reader/util']

>>> demo_reader.compressed.__path__

['/home/andrei/python/./path2/demo_reader/compressed']

Проверить, что всё работает как и до разбиения на части можно выполнив те же самые команды

>>> import sys >>> sys.path.extend(['./path1', './path2']) >>> from demo_reader.multireader import MultiReader >>> r = MultiReader('test.bz2') >>> r.read() 'data compressed with bz2'

Executable Directories

Рассмотрим проект из этого урока

python ├── multi-reader-program │ └── demo_reader │ ├── compressed │ │ ├── bzipped.py │ │ ├── gzipped.py │ │ └── __init__.py │ ├── __init__.py │ ├── multireader.py │ └── util │ ├── __init__.py │ └── writer.py ├── test.bz2 └── test.gz

Попытка выполнить директорию приведёт к ошибке

python multi-reader-program

/home/andrei/.pyenv/versions/3.9.5/bin/python: can't find '__main__' module in '/home/andrei/python/multi-reader-program'

Добавим в корень директории multi-reader-program файл __main__.py

# multi-reader-program/__main__.py print('executing multi-reader-program/__main__.py')

python multi-reader-program

executing multi-reader-program/__main__.py

Когда Python выполняет файл __main__.py он добавляет директорию в которой находится этот файл в sys.path затем из __main__.py можно импортировать любой скрипт из этой директории.

Изменим код __main__.py

# multi-reader-program/__main__.py import sys from demo_reader.multireader import MultiReader filename = sys.argv[1] r = MultiReader(filename) print(r.read()) r.close()

Теперь можно выполнить директорию

python multi-reader-program ./test.bz2

demo reader is being imported data compressed with bz2

Executable Zip Files

Рассмотрим код из предыдущего параграфа

python ├── multi-reader-program │ ├── demo_reader │ │ ├── compressed │ │ │ ├── bzipped.py │ │ │ ├── gzipped.py │ │ │ └── __init__.py │ │ ├── __init__.py │ │ ├── multireader.py │ │ └── util │ │ ├── __init__.py │ │ └── writer.py │ └── __main__.py ├── test.bz2 └── test.gz

cd multi-reader-program
python -m zipfile -c ../multi-reader-program.zip *
cd ..
ls

multi-reader-program multi-reader-program.zip test.bz2 test.gz

python multi-reader-program.zip test.gz

demo reader is being imported data compressed with gz by Andrei

Executable Package

Рассмотрим код из предыдущего параграфа, но директорию demo_reader вынесем из директории multi-reader-program

Добавим в директорию demo_reader файл __main__.py

ch4-executable-package ├── demo_reader │ ├── compressed │ │ ├── bzipped.py │ │ ├── gzipped.py │ │ └── __init__.py │ ├── __init__.py │ ├── __main__.py │ ├── multireader.py │ └── util │ ├── __init__.py │ └── writer.py ├── test.bz2 └── test.gz

python demo_reader test.gz

Traceback (most recent call last): File "/home/andrei/.pyenv/versions/3.9.5/lib/python3.9/runpy.py", line 197, in _run_module_as_main return _run_code(code, main_globals, None, File "/home/andrei/.pyenv/versions/3.9.5/lib/python3.9/runpy.py", line 87, in _run_code exec(code, run_globals) File "/home/andrei/python/demo_reader/__main__.py", line 7, in <module> from demo_reader.multireader import MultiReader ModuleNotFoundError: No module named 'demo_reader'

Выполнение директорий и пакетов отличается

python directory python -m directory
Выполняется директория Выполняется пакет

Опция -m указывает Python обращаться с directory как с модулем
directory добавляется в sys.path directory обрабатывается как пакет
directory/__main__.py не содержится в пакете directory/__main__.py это подмодуль пакета directory

В текущем примере, нужно обрабатывать demo_reader как модуль

python -m demo_reader test.gz

demo reader is being imported data compressed with gz

Похожие статьи
Пакеты в Python
Namespace пакеты в Python
Правильная структура пакета
setuptools
Плагины
Python