Namespace пакеты в Python
Введение | |
Поиск Namespace пакетов | |
Executable Directories | |
Executable Zip Files | |
Executable Packages | |
Похожие статьи |
Введение
Перед изучением этой статьи убедитесь, что вам знакома тема
sys.path в Python
PEP 420
Namespace пакеты это механизм, с помощью которого один Python пакет разбивается по различным
директориям на диске.
Так как директорий в корых находится namespace пакет несколько, не существует какого-то единого
__init__.py файла. Поэтому __init__.py файла
вообще может не быть.
При импорте namespace пакета никакой код не будет выполнен по умолчанию.
Поиск Namespace пакетов
- Сканирование всех директорий в sys.path
- Импорт стандартных пакетов, если они найдены
- Импорт стандартных модулей, если они найдены
- Если ничего не найдено - все подходящие директории подключаются к 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 |