Come scrivo i file __init__.py del pacchetto corretto / corretto


188

Il mio pacchetto ha la seguente struttura:

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

Non sono sicuro di come i __init__.pyfile debbano essere scritti correttamente.
Gli __init__.py #1assomiglia:

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

Ma come dovrebbe __init__.py #2apparire ad esempio ? Il mio è:

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

Quando dovrebbe essere __all__usato?


3
Tieni presente, tuttavia, che l'utilizzo dell'importazione * nel codice è generalmente una cattiva pratica e, se possibile, dovrebbe essere evitato. Ci sono pochissimi casi d'uso per questo, ma sono davvero rari.
Mayou36,

PSA: se sei interessato a imparare a scrivere buoni pacchetti di spazi dei nomi (il nuovo tipo di pacchetto), dai un'occhiata a questo pacchetto di esempio: github.com/pypa/sample-namespace-packages
Kyle

Risposte:


146

__all__è molto buono - aiuta a guidare le dichiarazioni di importazione senza importare automaticamente i moduli http://docs.python.org/tutorial/modules.html#importing-from-a-package

utilizzando __all__ed import *è ridondante, __all__è necessario solo

Penso che uno dei motivi più potenti da utilizzare import *in un __init__.pypacchetto di importazione sia quello di essere in grado di refactoring uno script che è cresciuto in più script senza rompere un'applicazione esistente. Ma se stai progettando un pacchetto dall'inizio. Penso che sia meglio lasciare i __init__.pyfile vuoti.

per esempio:

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

quindi l'app cresce e ora è un'intera cartella

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

allora lo script init può 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

in modo che uno script scritto per eseguire le seguenti operazioni non si interrompa durante la modifica:

from foo import fooFactory, tallFoo, shortFoo

3
Ero molto confuso riguardo all'importazione " tutto " e riga per riga. Il tuo esempio è molto illuminante.
Junchen,

2
Sono confuso da " __all__ed import *è ridondante", __all__viene utilizzato dal consumatore del modulo e from foo import *viene utilizzato dal modulo stesso per utilizzare altri ....
Nick T

using __all__ and import * is redundant, only __all__ is needed Come sono quelli ridondanti? Fanno cose diverse.
endolith,

113

I miei __init__.pyfile sono vuoti il ​​più delle volte. In particolare, non ho mai avuto una from blah import *parte di __init__.py- se "importare il pacchetto" significa ottenere tutti i tipi di classi, funzioni, ecc. Direttamente definiti come parte del pacchetto, quindi copierei lessicamente il contenuto del blah.pypacchetto __init__.pyinvece di rimuovere blah.py( la moltiplicazione dei file sorgente non va bene qui).

Se insisti nel sostenere gli import *idiomi (eek), usare __all__(con una minuscola lista di nomi che puoi farci avere) può aiutare a controllare i danni. In generale, gli spazi dei nomi e le importazioni esplicite sono buone cose e suggerisco vivamente di riconsiderare qualsiasi approccio basato sul bypass sistematico di uno o entrambi i concetti! -)


9
Personalmente, preferisco tenere le cose separate e quindi importare *. Il motivo è che, nonostante la piegatura e roba del genere, odio ancora sfogliare i file che contengono troppe classi, anche se correlate.
Stefano Borini,

5
@stefano pensa a un grande quadro. se lo usi import *devi accettare incondizionatamente tutto il framework nel suo insieme, anche le funzionalità che non utilizzerai mai. rimanere __init__.pyvuoti ti dà più possibilità di un semantico tutto o niente. pensa a contorto.
mg.

se lo tiene vuoto, anche dopo l'importazione di mobilescouter, non è ancora possibile utilizzare mobilescouter.mapper o mobilescouter.vehicle o mobilescouter.whatever. import mobilescouter.A., mobilescouter.B ..... troppo prolisso?
Sunqiang,

6
@sunqiang questo è personale ma io non la penso così. from mobilescouter import A, Bè solo una riga di codice e non hai un progetto con 666 classi e ognuno con il suo file, giusto? se ne hai due o più import *nel tuo codice, stai riempiendo lo spazio dei nomi con potenziali immondizie e rapidamente dimenticherai da dove Aprovengono. E se un pacchetto superiore fa lo stesso? stai afferrando tutti i sotto-pacchetti e sotto-pacchetti. come dice lo zen di Python, esplicito è meglio di implicito.
mg.

1
@mg, se c'è una riga "import A, B" nel file init .py, allora posso chiamare A (o B) con la sintassi: mobilescouter.A; se usiamo "dall'importazione mobile A, B", allora è solo A. qualcosa. a volte solo questa riga, non ricordo che A sia un sotto-pacakge di mobilescouter e penso che ciò contribuisca all'inquinamento dello spazio dei nomi (anche se è molto meglio di "" dall'importazione di mobilescouter * ". Preferisco ancora" import pkgname "dare all'utente l'interfaccia pubblica uniforme, quindi init .py fa le cose di sub_pkgname import.
sunqiang

1

Il tuo __init__.pydovrebbe avere un docstring .

Sebbene tutte le funzionalità siano implementate in moduli e pacchetti secondari, il docstring del pacchetto è il luogo in cui documentare da dove iniziare. Ad esempio, considera il pacchetto pythonemail . La documentazione del pacchetto è un'introduzione che descrive lo scopo, lo sfondo e il modo in cui i vari componenti all'interno del pacchetto lavorano insieme. Se generi automaticamente documentazione da docstring usando sphinx o un altro pacchetto, il docstring del pacchetto è esattamente il posto giusto per descrivere una simile introduzione.

Per qualsiasi altro contenuto, vedere le risposte eccellenti di firecrow e Alex Martelli .


L'effettivo __init__.pyper il emailpacchetto segue questa linea guida? Vedo una sola riga di dotstring che non fa molto per spiegare "come funzionano i vari componenti all'interno del pacchetto".
Gertlex,

@Gertlex Forse solo nella documentazione web.
Gerrit,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.