Comment écrire des fichiers __init__.py de package correct / correct

188

Mon colis a la structure suivante:

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
   ...

Je ne sais pas comment les __init__.pyfichiers doivent être correctement écrits.
Le __init__.py #1ressemble à:

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

Mais à quoi devrait par exemple __init__.py #2ressembler? Le mien est:

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

Quand faut-il l' __all__utiliser?

Marten Bauer
la source
3
Sachez cependant que l'utilisation de l'importation * dans le code est généralement une très mauvaise pratique et doit être évitée si possible. Il existe très peu de bons cas d'utilisation pour cela, mais ils sont vraiment rares.
Mayou36
PSA: si vous souhaitez apprendre à écrire de bons packages d'espace de noms (le nouveau type de package), consultez cet exemple de package: github.com/pypa/sample-namespace-packages
Kyle

Réponses:

146

__all__est très bon - il aide à guider les instructions d'importation sans importer automatiquement les modules http://docs.python.org/tutorial/modules.html#importing-from-a-package

en utilisant __all__et import *est redondant, seul __all__est nécessaire

Je pense que l'une des raisons les plus puissantes à utiliser import *dans un __init__.pypour importer des packages est de pouvoir refactoriser un script qui s'est développé en plusieurs scripts sans casser une application existante. Mais si vous concevez un package depuis le début. Je pense qu'il est préférable de laisser les __init__.pyfichiers vides.

par exemple:

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

puis l'application grandit et maintenant c'est un dossier entier

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

alors le script init peut dire

__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

afin qu'un script écrit pour faire ce qui suit ne se casse pas pendant le changement:

from foo import fooFactory, tallFoo, shortFoo
Corbeau de feu
la source
3
J'étais très confus à propos de « tout » et de l'importation ligne par ligne. Votre exemple est très éclairant.
Junchen
2
Je suis confus par " __all__et import *est redondant", __all__est utilisé par le consommateur du module, et from foo import *est utilisé par le module lui-même pour en utiliser d'autres ....
Nick T
using __all__ and import * is redundant, only __all__ is needed En quoi sont-ils redondants? Ils font des choses différentes.
endolith
113

Mes propres __init__.pyfichiers sont vides le plus souvent. En particulier, je n'ai jamais fait from blah import *partie de __init__.py- si "importer le package" signifie obtenir toutes sortes de classes, fonctions, etc. définies directement dans le cadre du package, alors je copierais lexicalement le contenu de blah.pydans le package à la __init__.pyplace et supprimerais blah.py( la multiplication des fichiers sources ne sert à rien ici).

Si vous insistez pour soutenir les import *idiomes (eek), alors utiliser __all__(avec une liste de noms aussi minuscule que vous pouvez vous en faire) peut aider à contrôler les dégâts. En général, les espaces de noms et les importations explicites sont de bonnes choses, et je suggère fortement de reconsidérer toute approche basée sur le contournement systématique de l'un ou des deux concepts! -)

Alex Martelli
la source
9
Personnellement, je préfère garder les choses séparées, puis importer *. La raison est que, malgré le pliage et les trucs, je déteste toujours parcourir les fichiers contenant trop de classes, même si elles sont liées.
Stefano Borini
5
@stefano pense à un grand framework. s'il l'utilise, import *vous devez accepter inconditionnellement tout le framework dans son ensemble, même les fonctionnalités que vous n'utiliserez jamais. rester __init__.pyvide vous donne plus de chances que la sémantique tout ou rien. pensez tordu.
mg.
si le garder vide, même après l'importation de mobilescouter, on ne peut toujours pas utiliser mobilescouter.mapper ou mobilescouter.vehicle ou mobilescouter.whatever. n'est pas import mobilecouter.A, mobilescouter.B ..... trop verbeux?
sunqiang
6
@sunqiang c'est personnel mais je ne pense pas. from mobilescouter import A, Best juste une ligne de code et vous n'avez pas de projet avec 666 classes et chacune avec son propre fichier, non? si vous en avez deux ou plus import *dans votre code, vous remplissez l'espace de noms avec des déchets potentiels et vous oublierez rapidement d'où Avient. Et si un emballage supérieur faisait de même? vous récupérez tous les sous-packages et sous-sous-packages. comme le dit le zen de python, l'explicite vaut mieux que l'implicite.
mg.
1
@mg, s'il y a une ligne "import A, B" dans le fichier init .py, alors je peux appeler le A (ou B) avec la syntaxe: mobilescouter.A; si nous utilisons "from mobilescouter import A, B", alors c'est juste A. quelque chose. parfois juste cette ligne, je ne me souviens pas que A est un sous-paquet de mobilescouter, et je pense que cela contribue à la pollution de l'espace de noms (même si c'est beaucoup mieux que "" from mobilescouter import * ". Je préfère toujours" import pkgname "donne à l'utilisateur l'interface publique uniforme. alors init .py faites les choses import sub_pkgname.
sunqiang
1

Votre __init__.pydevrait avoir un docstring .

Bien que toutes les fonctionnalités soient implémentées dans des modules et des sous-packages, votre package docstring est l'endroit pour documenter où commencer. Par exemple, considérons le package pythonemail . La documentation du package est une introduction décrivant l'objectif, le contexte et la manière dont les différents composants du package fonctionnent ensemble. Si vous générez automatiquement de la documentation à partir de docstrings en utilisant sphinx ou un autre package, le package docstring est exactement le bon endroit pour décrire une telle introduction.

Pour tout autre contenu, consultez les excellentes réponses de Firecrow et Alex Martelli .

gerrit
la source
Le contenu réel __init__.pydu emailcolis suit-il cette directive? Je vois une docstring sur une seule ligne qui ne fait pas grand-chose pour expliquer "comment les différents composants du package fonctionnent ensemble".
Gertlex
@Gertlex Peut-être uniquement dans la documentation Web.
gerrit