Пакеты «внутри» модулей

#python #module #python-3.x #package #packaging

#python #модуль #python-3.x #пакет #упаковка

Вопрос:

У меня растет количество скриптов, составляющих программу, которую я пишу, и я решил, что пришло время очистить мое дерево исходных текстов и правильно их упаковать. Я уверен, что это простой вопрос, но я не могу выяснить, как это сделать.

Если у меня есть группа модулей, которые подходят друг другу, но один должен быть модулем верхнего уровня, а остальные должны иметь префикс имени модуля, но на самом деле переходить в пакеты более низкого уровня, как я могу это сделать.

Например, скажем, я хотел иметь возможность import mystuff и получить весь mystuff. но я также должен уметь import mystuff.test.test1 . Я думал, что создам исходное дерево, подобное этому,

 myprogram/
    mystuff.py
    mystuff/
        __init__.py
        tests/
            __init__.py
            test1.py
            test2.py
            ...
  

Но в этом случае, похоже, он mystuff/ всегда имеет приоритет над mystuff.py , поэтому import mystuff ничего не делает (пока mystuff/ ‘s __init__.py пуст).

Каким был бы правильный подход для получения желаемого поведения? Или это невозможно, и я должен перейти mystuff.py в mystuff/ и получить к нему доступ как mystuff.mystuff (кажется, это ненужное повторение).

Извините, если я только что пропустил что-то очевидное. Я предполагаю, что это должно быть где-то задокументировано, но, похоже, я не могу найти, где что-то есть.

Обновить.Хотя я считаю, что метод Игнасио является правильным, мне это не очень нравится! Если у меня открыто несколько файлов в моем редакторе, и все они вызываются __init__.py , все может запутаться. Итак, я решил оставить свою структуру такой, какая она есть, и связать mystuff.py с mystuff/__init__.py . Если у кого-нибудь есть какие-либо мнения о том, почему я не должен этого делать, я хотел бы их услышать.

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

Комментарии:

1. ДА. Вы не должны этого делать, потому что ответ Ignatio является правильным.

2. @cwallenpoole. Согласен, но в конце концов, то, как я его настроил, дает точно тот же эффект. Даже sdist выходные данные будут точно такими же, как у Игнасио, без моих ссылок. Так что это просто облегчает мне разработку. Есть ли какая-то другая причина, по которой это плохо делать?

Ответ №1:

Вместо этого все, что находится в mystuff.py , должно быть помещено в mystuff/__init__.py .

Комментарии:

1. Я думал об этом. Но это казалось немного неприятным способом сделать это. Это все же рекомендуемый метод? Если да, то это то, что я сделаю, или это просто «способ, который будет работать»? Спасибо за ваш ответ.

2. Вот как это делается. Все, что находится в, foo/__init__.py станет частью foo при импорте.

3. ОК. Тогда это здорово. Вот так просто 🙂 Большое спасибо. (Будет приниматься, когда разрешено)

4. Вероятно, это должен быть отдельный вопрос, но поскольку это может быть просто быстрый ответ «да / нет», мне интересно, могу ли я спросить. Если mystuff.py это действительно скомпилированный mystuff.so (я использую cython), будет ли это по-прежнему работать. То есть будет __init__.so прочитан, если он существует?

5. Я не знаю наверняка, но я бы не стал это пробовать. Сделайте модуль C отдельным и импортируйте из него в __init__.py .

Ответ №2:

У вас не может быть одновременно mystuff.py и mystuff/ пакета.

У вас есть два варианта:

  • поместите код в mystuff.py в mystuff/__init__.py
  • переименуйте mystuff.py , например, в mystuff/_stuff.py , а затем импортируйте это в mystuff/__init__.py .

Второй вариант выглядит примерно так:

 myprogram/
    mystuff.py -------
    mystuff/           
        __init__.py    /
        _stuff.py <---
        tests/
            __init__.py
            test1.py
            test2.py
            ...
  

и mystuff/__init__.py выглядит как:

 from mystuff._stuff import *