Как мне написать хорошие / правильные файлы пакета __init__.py

188

Моя посылка имеет следующую структуру:

mobilescouter/
    __init__.py #1
    mapper/
        __init__.py  #2
        lxml/
            __init__.py #3
            vehiclemapper.py
            vehiclefeaturemapper.py
            vehiclefeaturesetmapper.py
        ...
        basemapper.py
   vehicle/
        __init__.py #4
        vehicle.py
        vehiclefeature.py
        vehiclefeaturemapper.py
   ...

Я не уверен, как __init__.pyфайлы должны быть правильно написаны.
В __init__.py #1выглядит следующим образом :

__all__ = ['mapper', 'vehicle']
import mapper
import vehicle

Но как, например, должно __init__.py #2выглядеть? Мой это:

__all__ = ['basemapper', 'lxml']
from basemaper import *
import lxml

Когда следует __all__использовать?

Мартен Бауэр
источник
3
Имейте в виду, что использование import * в коде, как правило, очень плохая практика, и ее следует избегать, если это возможно. Хороших вариантов использования для этого очень мало, но они действительно редки.
Mayou36
PSA: если вы заинтересованы в том, чтобы научиться писать хорошие пакеты пространства имен (новый тип пакета), посмотрите этот пример пакета: github.com/pypa/sample-namespace-packages
Kyle

Ответы:

146

__all__это очень хорошо - это помогает направлять операторы импорта без автоматического импорта модулей http://docs.python.org/tutorial/modules.html#importing-from-a-package

использование __all__и import *является избыточным, __all__требуется только

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

например:

foo.py - contains classes related to foo such as fooFactory, tallFoo, shortFoo

то приложение растет и теперь это целая папка

foo/
    __init__.py
    foofactories.py
    tallFoos.py
    shortfoos.py
    mediumfoos.py
    santaslittlehelperfoo.py
    superawsomefoo.py
    anotherfoo.py

тогда скрипт инициализации может сказать

__all__ = ['foofactories', 'tallFoos', 'shortfoos', 'medumfoos',
           'santaslittlehelperfoo', 'superawsomefoo', 'anotherfoo']
# deprecated to keep older scripts who import this from breaking
from foo.foofactories import fooFactory
from foo.tallfoos import tallFoo
from foo.shortfoos import shortFoo

чтобы сценарий, написанный для выполнения следующих действий, не прерывался во время изменения:

from foo import fooFactory, tallFoo, shortFoo
Огненная ворона
источник
3
Я был очень смущен « все » и построчным импортом. Ваш пример очень яркий.
Junchen
2
Я сбит с толку " __all__и import *является избыточным", __all__используется потребителем модуля и from foo import *используется самим модулем для использования других ....
Ник Т
using __all__ and import * is redundant, only __all__ is needed Как эти излишни? Они делают разные вещи.
эндолиты
113

Мои собственные __init__.pyфайлы чаще всего пусты. В частности, у меня никогда не было from blah import *части __init__.py- если «импорт пакета» означает получение всех видов классов, функций и т. Д., Определенных непосредственно как часть пакета, то я бы вместо этого скопировал содержимое blah.pyв пакет __init__.pyи удалил blah.py( умножение исходных файлов здесь не годится).

Если вы настаиваете на поддержке import *идиом (eek), то использование __all__(с минимальным списком имен, который вы можете себе представить) может помочь в контроле за ущербом. В общем, пространства имен и явный импорт - это хорошо , и я настоятельно рекомендую пересмотреть любой подход, основанный на систематическом обходе одного или обоих понятий! -)

Алекс Мартелли
источник
9
Лично я предпочитаю хранить вещи отдельно, а затем импортировать *. Причина в том, что, несмотря на свертывание и прочее, я все еще ненавижу просматривать файлы, содержащие слишком много классов, даже если они связаны между собой.
Стефано Борини
5
@Stefano думать о больших рамках. если он использует, import *вы должны безоговорочно принять все фреймворки, даже те функции, которые вы никогда не будете использовать. сохраняя __init__.pyпустой даст вам больше шансов , чем просто все или ничего семантического. думать о витой
мг
если оставить его пустым, даже после импорта mobilescouter, вы все равно не сможете использовать mobilescouter.mapper или mobilescouter.vehicle или mobilescouter.whither. не импортирует mobilescouter.A, mobilescouter.B ..... слишком многословно?
Sunqiang
6
@ Sunqiang это личное, но я так не думаю. from mobilescouter import A, Bэто всего лишь строка кода, и у вас нет проекта с 666 классами и у каждого свой файл, верно? если import *в вашем коде их два или более, вы заполняете пространство имен потенциальным мусором и быстро забудете, откуда они Aберутся. А если верхний пакет сделать тоже самое? вы захватываете все подпакеты и подпакеты. как говорит дзен питона, явное лучше, чем неявное.
мг
1
@mg, если в файле init .py есть строка «import A, B» , то я могу вызвать A (или B) с синтаксисом: mobilescouter.A; если мы используем «из импорта мобильных устройств A, B», то это просто А. что-то. иногда я не помню, чтобы эта строка была подпакетом mobilescouter, и я думаю, что это способствует загрязнению пространства имен (хотя это намного лучше, чем "" из импорта mobilescouter * ". Я все еще предпочитаю" import pkgname "предоставить пользователю единый общедоступный интерфейс. поэтому init .py выполняет импорт sub_pkgname.
Sunqiang
1

У тебя __init__.pyдолжна быть документальная строка .

Хотя вся функциональность реализована в модулях и подпакетах, строка документации вашего пакета - это то место, где нужно документировать, с чего начать. Например, рассмотрим пакет pythonemail . Документация пакета представляет собой введение, описывающее цель, фон и то, как различные компоненты в пакете работают вместе. Если вы автоматически генерируете документацию из строк документации, используя sphinx или другой пакет, пакет документации doc является именно тем местом, где можно описать такое введение.

Для любого другого контента, посмотрите отличные ответы от Firecrow и Alex Martelli .

Геррит
источник
Соответствует ли фактическое __init__.pyдля emailпакета это руководство? Я вижу одну строку документации, которая мало что объясняет, «как различные компоненты в пакете работают вместе».
Гертлекс
@Gertlex Возможно только в веб-документации.
Геррит