Правильно ли я использую пакеты пространств имен?

Вопрос или проблема

Я начинающий разработчик на Python. Я пытаюсь узнать лучший способ использования пакетов, но сталкиваюсь с проблемами при их сборке и развертывании. Моя настройка:

  • Python 3.13+ без необходимости совместимости с версиями до Python 3.9.
  • Структура кода “src” (согласно https://packaging.python.org/).
  • “pyproject.toml” для конфигурации пакета, потому что это, похоже, новый стандарт.
  • “hatchling” для сборки, но я открыт для альтернатив.

Допустим, я работаю в организации “acme”. Есть много небольших проектов на Python только для внутреннего использования, которые я хочу развернуть под пространством имен “acme”.

Допустим также, что один из таких внутренних проектов – “kitchentool”. Вот как я хочу, чтобы он использовался в python-скриптах:

import acme.kitchentool

или

from acme.kitchentool import KitchenTool

Этот проект имеет несколько утилит командной строки, и вот как я хочу, чтобы они вызывались
(я могу убрать подсистему ‘cmd’, если это не является питоничным, но мне нравится разделение исходного кода):

$ python -m acme.kitchentool.cmd.cut --fine
$ python -m acme.kitchentool.cmd.blend --speed 60
$ python -m acme.kitchentool.cmd.roast --temp 350

Вот моя текущая структура исходников, с которой у меня возникают трудности:

acme_kitchentool/   # Корень исходного кода для этого проекта
|-- README.md
|-- pyproject.toml
|-- src/                # Я крайне предпочитаю это 'src' к 'плоской' структуре, по причинам.
    |                       # Нет __init__.py в директории src.
    |-- acme/
        |                       # Нет __init__.py в src/acme (пространство имен).
        |-- kitchentool.py          # Ключевые классы/функции.
        |-- kitchentool/            # Эта директория в порядке, если у меня также есть kitchentool.py?
            |-- __init__.py             # Пустой __init__.py
            |-- cmd/                    # Подпакет для утилит командной строки
                |-- __init__.py             # Пустой __init__.py
                |-- chop.py                 # Утилита командной строки
                |-- blend.py                # Утилита командной строки
                |-- roast.py                # Утилита командной строки
                        

Вопросы:

  1. Можно ли иметь как файл kitchentool.py, так и подпапку kitchentool/, как показано?

  2. Если нет, то какой правильный способ добиться желаемого? Должен ли kitchentool.py быть __init__.py в директории kitchentool/?

  3. Правильны ли у меня файлы __init__.py?

  4. Является ли cmd технически пространством имен, которое не должно иметь __init__.py, согласно https://packaging.python.org/en/latest/guides/packaging-namespace-packages/?

Крайне важно, чтобы каждая дистрибуция, использующая пространство имен, не имела init.py или использовала стиль init для pkgutil. Если какая-либо дистрибуция этого не сделает, это приведет к неудаче логики пространства имен, и другие подсистемы не будут доступными для импорта.

Буду рад любым советам. Спасибо!

Ответ или решение

Оценка использования пространств имен в Python-пакетах

Приветствую вас! Отлично, что вы изучаете создание и организацию Python-пакетов. Ваша ситуация с пространствами имен (namespace packages) довольно типична, и давайте рассмотрим основные вопросы и проблемы, которые у вас возникли.

1. Возможно ли иметь как файл kitchentool.py, так и подкаталог kitchentool/?

Да, наличие как файла kitchentool.py, так и подкаталога kitchentool/ в одной и той же структуре пакета допустимо, но не рекомендуемая практика в данной археологии. Если вы хотите иметь обе структуры, это может привести к путанице при импорте и определении, что следует импортировать, особенно если они имеют схожие имена классов или функций. Лучше всего, если вы определите, что именно должно содержаться в вашем проекте, и использовать одно из этих решений:

  • Если вы хотите организовать более сложную логику внутри kitchentool, рекомендуем использовать только подкаталог kitchentool/ как главный модуль пакета.
  • Либо оставьте только kitchentool.py, если логика достаточно проста.

2. Как правильно организовать структуру, если не следует иметь оба?

Если вы решите пойти по пути структуры с подкаталогом kitchentool/, вам следует сделать __init__.py в этом каталоге основным модулем вашего проекта, и переместить содержимое kitchentool.py в kitchentool/__init__.py. Это обеспечит ясность для вашего пакета:

src/
|-- acme/
    |-- kitchentool/
        |-- __init__.py  # Ваши классы и функции теперь здесь
        |-- cmd/
            |-- __init__.py  # Как указано ниже, в нем не должно быть содержания
            |-- chop.py
            |-- blend.py
            |-- roast.py

С этим изменением вы сможете использовать код как в примерах import acme.kitchentool, так и как from acme.kitchentool import KitchenTool.

3. Верны ли мои файлы __init__.py?

Ваша текущая структура __init__.py для подкаталогов в целом правильная. Однако важно, чтобы:

  • kitchentool/__init__.py содержал код, который должен быть доступен при импорте в acme.kitchentool.
  • cmd/__init__.py может оставаться пустым, если вы не планируете явным образом определять какие-либо функции или классы, которые должны быть доступны на уровне acme.kitchentool.cmd.

Если cmd будет использоваться только как подкаталог для скриптов, вы можете не включать в него __init__.py, так как это позволит избежать путаницы и будет полностью соответствовать концепции пространств имен.

4. Должен ли cmd быть пространством имен?

В контексте использования пространства имен cmd не является необходимым пространством имен, поскольку это всего лишь подкаталог, отвечающий за команды. Вы можете оставить __init__.py в этом каталоге как пустой файл или даже его убрать, так как он не требует пространственной логики, если все обрабатывается в текущем контексте.

Тем не менее, если у вас есть предположение о будущих расширениях, и вы хотите позволить нескольким разработчикам добавлять командные утилиты в различные модули с cmd, то структура с __init__.py может оказаться более подходящей.

Заключение

На основании вашего опыта и трудностей, с которыми вы столкнулись, рекомендуем реализовать один основной файл и один вспомогательный подкаталог. Это поможет избежать путаницы и обеспечит более чистую архитектуру. Ваши текущие проблемы, вероятно, возникли из-за смешивания двух методов. Попробуйте пересмотреть вашу архитектуру с учетом указаний выше, и это должно значительно улучшить вашу организацию проекта.

Если у вас возникнут дополнительные вопросы или вам нужна помощь в дальнейших этапах разработки, всегда рады помочь! Удачи в программировании!

Оцените материал
Добавить комментарий

Капча загружается...