Risposte:
È un elenco di oggetti pubblici di quel modulo, come interpretato da import *
. Sostituisce l'impostazione predefinita di nascondere tutto ciò che inizia con un carattere di sottolineatura.
import *
(come ad es tk
.). Un buon suggerimento in questo caso è la presenza __all__
o nomi che iniziano con il trattino basso nel codice del modulo.
tk
fossero stati rilasciati oggi (o anche nel 2012), la pratica raccomandata sarebbe quella di utilizzare from tk import *
. Penso che la pratica sia accettata per inerzia, non per progettazione intenzionale.
Collegato a, ma non esplicitamente menzionato qui, è esattamente quando __all__
viene utilizzato. È un elenco di stringhe che definisce quali simboli verranno esportati in un modulo quando from <module> import *
viene utilizzato sul modulo.
Ad esempio, il codice seguente foo.py
esporta esplicitamente i simboli bar
e baz
:
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'
Questi simboli possono quindi essere importati in questo modo:
from foo import *
print(bar)
print(baz)
# The following will trigger an exception, as "waz" is not exported by the module
print(waz)
Se quanto __all__
sopra è commentato, questo codice verrà eseguito fino al completamento, poiché il comportamento predefinito di import *
è quello di importare tutti i simboli che non iniziano con un carattere di sottolineatura, dallo spazio dei nomi indicato.
Riferimento: https://docs.python.org/tutorial/modules.html#importing-from-a-package
NOTA: __all__
influisce from <module> import *
solo sul comportamento. I membri non menzionati in __all__
sono ancora accessibili dall'esterno del modulo e possono essere importati con from <module> import <member>
.
print(baz())
?
print(baz)
stampa qualcosa di simile <function baz at 0x7f32bc363c10>
mentre print(baz())
stampabaz
Spiega __all__ in Python?
Continuo a vedere la variabile
__all__
impostata in diversi__init__.py
file.Cosa fa questo?
__all__
?Dichiara i nomi semanticamente "pubblici" da un modulo. Se è presente un nome __all__
, gli utenti devono usarlo e possono aspettarsi che non cambi.
Avrà anche effetti programmatici:
import *
__all__
in un modulo, ad esempio module.py
:
__all__ = ['foo', 'Bar']
significa che quando vieni import *
dal modulo, __all__
vengono importati solo quei nomi nel :
from module import * # imports foo and Bar
Gli strumenti di completamento automatico della documentazione e del codice possono (in effetti, dovrebbero) ispezionare anche __all__
per determinare quali nomi mostrare come disponibili da un modulo.
__init__.py
rende una directory un pacchetto PythonDai documenti :
I
__init__.py
file sono necessari per fare in modo che Python tratti le directory come pacchetti contenenti; ciò viene fatto per impedire alle directory con un nome comune, come stringa, di nascondere involontariamente moduli validi che si verificano successivamente nel percorso di ricerca del modulo.Nel caso più semplice,
__init__.py
può essere solo un file vuoto, ma può anche eseguire il codice di inizializzazione per il pacchetto o impostare la__all__
variabile.
Quindi __init__.py
può dichiarare il __all__
per un pacchetto .
Un pacchetto è in genere costituito da moduli che possono importarsi a vicenda, ma che sono necessariamente collegati insieme a un __init__.py
file. Quel file è ciò che rende la directory un vero pacchetto Python. Ad esempio, supponiamo di avere i seguenti file in un pacchetto:
package
├── __init__.py
├── module_1.py
└── module_2.py
Creiamo questi file con Python in modo da poter seguire insieme: potresti incollare quanto segue in una shell Python 3:
from pathlib import Path
package = Path('package')
package.mkdir()
(package / '__init__.py').write_text("""
from .module_1 import *
from .module_2 import *
""")
package_module_1 = package / 'module_1.py'
package_module_1.write_text("""
__all__ = ['foo']
imp_detail1 = imp_detail2 = imp_detail3 = None
def foo(): pass
""")
package_module_2 = package / 'module_2.py'
package_module_2.write_text("""
__all__ = ['Bar']
imp_detail1 = imp_detail2 = imp_detail3 = None
class Bar: pass
""")
E ora hai presentato un'API completa che qualcun altro può usare quando importano il tuo pacchetto, in questo modo:
import package
package.foo()
package.Bar()
E il pacchetto non avrà tutti gli altri dettagli di implementazione utilizzati durante la creazione dei moduli che ingombrano lo package
spazio dei nomi.
__all__
in __init__.py
Dopo ulteriori lavori, forse hai deciso che i moduli sono troppo grandi (come molte migliaia di linee?) E devono essere suddivisi. Quindi fai quanto segue:
package
├── __init__.py
├── module_1
│ ├── foo_implementation.py
│ └── __init__.py
└── module_2
├── Bar_implementation.py
└── __init__.py
Per prima cosa crea le directory dei pacchetti secondari con gli stessi nomi dei moduli:
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
Sposta le implementazioni:
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
creare __init__.py
s per i pacchetti secondari che dichiarano __all__
per ciascuno:
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
E ora hai ancora l'API fornito a livello di pacchetto:
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
E puoi facilmente aggiungere elementi all'API che puoi gestire a livello di subpackage anziché a livello di modulo del subpackage. Se si desidera aggiungere un nuovo nome all'API, è sufficiente aggiornare __init__.py
, ad esempio in module_2:
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
E se non sei pronto a pubblicare Baz
nell'API di livello superiore, nel tuo livello superiore __init__.py
potresti avere:
from .module_1 import * # also constrained by __all__'s
from .module_2 import * # in the __init__.py's
__all__ = ['foo', 'Bar'] # further constraining the names advertised
e se i tuoi utenti sono a conoscenza della disponibilità di Baz
, possono usarlo:
import package
package.Baz()
ma se non lo conoscono, altri strumenti (come pydoc ) non li informeranno.
In seguito puoi cambiarlo quando Baz
è pronto per la prima serata:
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
_
contro __all__
:Per impostazione predefinita, Python esporterà tutti i nomi che non iniziano con un _
. Certamente potresti fare affidamento su questo meccanismo. Alcuni pacchetti nella libreria standard di Python, infatti, si basano su questo, ma per fare ciò, alias le loro importazioni, ad esempio in ctypes/__init__.py
:
import os as _os, sys as _sys
L'uso della _
convenzione può essere più elegante perché rimuove la ridondanza di denominare nuovamente i nomi. Ma aggiunge la ridondanza per le importazioni (se ne hai molte) ed è facile dimenticare di farlo in modo coerente - e l'ultima cosa che vuoi è dover supportare indefinitamente qualcosa che intendi essere solo un dettaglio di implementazione, solo perché hai dimenticato di aggiungere un prefisso _
quando hai assegnato un nome a una funzione.
Personalmente scrivo una __all__
prima parte del mio ciclo di vita di sviluppo per i moduli in modo che altri che potrebbero usare il mio codice sappiano cosa dovrebbero usare e non usare.
La maggior parte dei pacchetti nella libreria standard usa anche __all__
.
__all__
ha sensoHa senso attenersi alla _
convenzione del prefisso al posto di __all__
quando:
export
decoratoreIl rovescio della medaglia dell'uso __all__
è che devi scrivere i nomi delle funzioni e delle classi esportate due volte - e le informazioni sono mantenute separate dalle definizioni. Abbiamo potuto usare un decoratore per risolvere questo problema.
Ho avuto l'idea di un tale decoratore di esportazione dal discorso di David Beazley sul packaging. Questa implementazione sembra funzionare bene nel tradizionale importatore di CPython. Se hai un hook o un sistema di importazione speciale, non lo garantisco, ma se lo adotti, è abbastanza banale tornare indietro - dovrai solo aggiungere manualmente i nomi nel__all__
Quindi, ad esempio, in una libreria di utilità, dovresti definire il decoratore:
import sys
def export(fn):
mod = sys.modules[fn.__module__]
if hasattr(mod, '__all__'):
mod.__all__.append(fn.__name__)
else:
mod.__all__ = [fn.__name__]
return fn
e quindi, dove definiresti un __all__
, fai questo:
$ cat > main.py
from lib import export
__all__ = [] # optional - we create a list if __all__ is not there.
@export
def foo(): pass
@export
def bar():
'bar'
def main():
print('main')
if __name__ == '__main__':
main()
E questo funziona bene se eseguito come principale o importato da un'altra funzione.
$ cat > run.py
import main
main.main()
$ python run.py
main
E anche il provisioning API con import *
funzionerà:
$ cat > run.py
from main import *
foo()
bar()
main() # expected to error here, not exported
$ python run.py
Traceback (most recent call last):
File "run.py", line 4, in <module>
main() # expected to error here, not exported
NameError: name 'main' is not defined
@export
decoratore.
__init__.py
e l'uso di__all__
__all__
sia corretto.
__all__
anche il tuo - ma poi direi che hai un'API instabile ... Questo sarebbe qualcosa su cui avere alcuni test di accettazione completi.
module_1
e module_2
; va bene includere un esplicito del module_1
in __init__.py
? Sbaglio a pensare che valga la pena?
Sto solo aggiungendo questo per essere precisi:
Tutte le altre risposte si riferiscono ai moduli . La domanda originale menzionata esplicitamente __all__
nei __init__.py
file, quindi si tratta di pacchetti Python .
In genere, __all__
entra in gioco solo quando viene utilizzata la from xxx import *
variante import
dell'istruzione. Questo vale sia per i pacchetti che per i moduli.
Il comportamento dei moduli è spiegato nelle altre risposte. L'esatto comportamento dei pacchetti è descritto qui in dettaglio.
In breve, __all__
a livello di pacchetto fa all'incirca la stessa cosa dei moduli, tranne per il fatto che si occupa di moduli all'interno del pacchetto (al contrario di specificare i nomi all'interno del modulo ). __all__
Specifica quindi tutti i moduli che devono essere caricati e importati nello spazio dei nomi corrente quando li utilizziamo from package import *
.
La grande differenza è che quando si omette la dichiarazione di __all__
in un pacchetto __init__.py
, la dichiarazione from package import *
non importerà nulla (con le eccezioni spiegate nella documentazione, vedere il link sopra).
D'altra parte, se si omette __all__
in un modulo, l '"importazione speciale" importerà tutti i nomi (che non iniziano con un carattere di sottolineatura) definiti nel modulo.
from package import *
importerà comunque tutto ciò che è stato definito __init__.py
, anche se non è presente all
. La differenza importante è che senza di __all__
essa non verranno importati automaticamente i moduli definiti nella directory del pacchetto.
Cambia anche ciò che mostrerà Pydoc:
module1.py
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc module1
Aiuto sul modulo module1: NOME modulo 1 FILE module1.py DATI a = 'A' b = 'B' c = 'C'
$ pydoc module2
Aiuto sul modulo module2: NOME Module2 FILE module2.py DATI __all__ = ['a', 'b'] a = 'A' b = 'B'
Dichiaro __all__
in tutti i miei moduli, oltre a sottolineare i dettagli interni, che sono di grande aiuto quando si usano cose che non si sono mai usate prima in sessioni di interpretazione dal vivo.
__all__
personalizza *
infrom <module> import *
__all__
personalizza *
infrom <package> import *
Un modulo è un .py
file destinato ad essere importato.
Un pacchetto è una directory con un __init__.py
file. Un pacchetto di solito contiene moduli.
""" cheese.py - an example module """
__all__ = ['swiss', 'cheddar']
swiss = 4.99
cheddar = 3.99
gouda = 10.99
__all__
fa conoscere agli umani le funzionalità "pubbliche" di un modulo . [ @AaronHall ] Inoltre, pydoc li riconosce. [ @Longpoke ]
Guarda come swiss
e cheddar
vengono portati nello spazio dei nomi locale, ma non gouda
:
>>> from cheese import *
>>> swiss, cheddar
(4.99, 3.99)
>>> gouda
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'gouda' is not defined
Senza __all__
, nessun simbolo (che non inizia con un trattino basso) sarebbe stato disponibile.
*
non sono interessate da__all__
>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)
>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)
>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)
Nel __init__.py
file di un pacchetto __all__
è presente un elenco di stringhe con i nomi di moduli pubblici o altri oggetti. Queste funzionalità sono disponibili per l'importazione di caratteri jolly. Come per i moduli, __all__
personalizza l' *
importazione di caratteri jolly dal pacchetto. [ @MartinStettner ]
Ecco un estratto dal connettore MySQL Python __init__.py
:
__all__ = [
'MySQLConnection', 'Connect', 'custom_error_exception',
# Some useful constants
'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
'HAVE_CEXT',
# Error handling
'Error', 'Warning',
...etc...
]
Il caso predefinito, l' asterisco senza __all__
un pacchetto , è complicato, perché il comportamento ovvio sarebbe costoso: utilizzare il file system per cercare tutti i moduli nel pacchetto. Invece, nella mia lettura dei documenti, __init__.py
vengono importati solo gli oggetti definiti in :
Se
__all__
non è definito, la dichiarazionefrom sound.effects import *
non non importa tutti i sottomoduli il pacchettosound.effects
nello spazio dei nomi corrente; assicura solo che il pacchettosound.effects
sia stato importato (possibilmente eseguendo qualsiasi codice di inizializzazione in__init__.py
) e quindi importa qualunque nome sia definito nel pacchetto. Ciò include tutti i nomi definiti (e sottomoduli caricati esplicitamente) da__init__.py
. Include anche tutti i sottomoduli del pacchetto che sono stati esplicitamente caricati da precedenti dichiarazioni di importazione.
Le importazioni di caratteri jolly ... dovrebbero essere evitate in quanto [confondono] i lettori e molti strumenti automatici.
[ PEP 8 , @ToolmakerSteve]
from <package> import *
senza__all__
a __init__.py
che non importare qualsiasi modulo .
__init__.py
fosse un modulo . Ma non sono sicuro che sia accurato, o in particolare se gli oggetti con prefisso di sottolineatura sono esclusi. Inoltre, ho separato più chiaramente le sezioni su MODULI e PACCHETTI. I vostri pensieri?
Da (An Unofficial) Python Reference Wiki :
I nomi pubblici definiti da un modulo sono determinati controllando lo spazio dei nomi del modulo per una variabile denominata
__all__
; se definito, deve essere una sequenza di stringhe che sono nomi definiti o importati da quel modulo. I nomi indicati__all__
sono tutti considerati pubblici e devono esistere. Se__all__
non è definito, l'insieme di nomi pubblici include tutti i nomi trovati nello spazio dei nomi del modulo che non iniziano con un carattere di sottolineatura ("_").__all__
dovrebbe contenere l'intera API pubblica. Ha lo scopo di evitare l'esportazione accidentale di elementi che non fanno parte dell'API (come i moduli di libreria che sono stati importati e utilizzati all'interno del modulo).
__all__
è usato per documentare l'API pubblica di un modulo Python. Sebbene sia facoltativo,__all__
dovrebbe essere utilizzato.
Ecco l'estratto pertinente dal riferimento al linguaggio Python :
I nomi pubblici definiti da un modulo sono determinati controllando lo spazio dei nomi del modulo per una variabile denominata
__all__
; se definito, deve essere una sequenza di stringhe che sono nomi definiti o importati da quel modulo. I nomi indicati__all__
sono tutti considerati pubblici e devono esistere. Se__all__
non è definito, l'insieme di nomi pubblici include tutti i nomi trovati nello spazio dei nomi del modulo che non iniziano con un carattere di sottolineatura ('_').__all__
dovrebbe contenere l'intera API pubblica. Ha lo scopo di evitare l'esportazione accidentale di elementi che non fanno parte dell'API (come i moduli di libreria che sono stati importati e utilizzati all'interno del modulo).
PEP 8 utilizza una formulazione simile, sebbene chiarisca anche che i nomi importati non fanno parte dell'API pubblica quando __all__
è assente:
Per supportare meglio l'introspezione, i moduli dovrebbero dichiarare esplicitamente i nomi nella loro API pubblica usando l'
__all__
attributo. Ambientazione__all__
su un elenco vuoto indica che il modulo non ha API pubbliche.[...]
I nomi importati devono sempre essere considerati un dettaglio di implementazione. Altri moduli non devono fare affidamento sull'accesso indiretto a tali nomi importati a meno che non siano una parte esplicitamente documentata dell'API del modulo contenitore, come
os.path
un__init__
modulo del pacchetto o che espone funzionalità dai sottomoduli.
Inoltre, come sottolineato in altre risposte, __all__
viene utilizzato per abilitare l' importazione di caratteri jolly per i pacchetti :
L'istruzione import utilizza la seguente convenzione: se il
__init__.py
codice di un pacchetto definisce un elenco denominato__all__
, viene considerato l'elenco dei nomi dei moduli che devono essere importati quandofrom package import *
viene rilevato.
__all__
colpisce from <module> import *
dichiarazioni.
Considera questo esempio:
foo
├── bar.py
└── __init__.py
In foo/__init__.py
:
(Implicito) Se non lo definiamo __all__
, from foo import *
importeremo solo i nomi definiti in foo/__init__.py
.
(Esplicito) Se definiamo __all__ = []
, quindi from foo import *
non importerò nulla.
(Esplicito) Se lo definiamo __all__ = [ <name1>, ... ]
, from foo import *
importeremo solo quei nomi.
Si noti che nel caso implicito, python non importerà i nomi che iniziano con _
. Tuttavia, è possibile forzare l'importazione di tali nomi tramite__all__
.
Puoi visualizzare il documento Python qui .
__all__
influenza come from foo import *
funziona.
Il codice che si trova all'interno di un corpo del modulo (ma non nel corpo di una funzione o di una classe) può usare un asterisco ( *
) in from
un'istruzione:
from foo import *
Le *
richieste che tutti gli attributi del modulo foo
(tranne quelli che iniziano con i trattini bassi) siano associati come variabili globali nel modulo di importazione. Quando foo
ha un attributo __all__
, il valore dell'attributo è l'elenco dei nomi associati a questo tipo difrom
istruzione.
Se foo
è un pacchetto e __init__.py
definisce un elenco denominato __all__
, viene considerato l'elenco dei nomi dei sottomoduli che devono essere importati quando from foo import *
viene rilevato. Se __all__
non è definito, l'istruzione from foo import *
importa tutti i nomi definiti nel pacchetto. Ciò include tutti i nomi definiti (e sottomoduli caricati esplicitamente) da __init__.py
.
Nota che __all__
non deve essere un elenco. Secondo la documentazione import
sull'istruzione , se definita, __all__
deve essere una sequenza di stringhe che sono nomi definiti o importati dal modulo. Quindi puoi anche usare una tupla per salvare alcuni cicli di memoria e CPU. Basta non dimenticare una virgola nel caso in cui il modulo definisca un singolo nome pubblico:
__all__ = ('some_name',)
Vedi anche Perché "import *" è male?
Questo è definito in PEP8 qui :
Nomi delle variabili globali
(Speriamo che queste variabili siano destinate all'uso all'interno di un solo modulo.) Le convenzioni sono quasi uguali a quelle per le funzioni.
I moduli progettati per essere utilizzati tramite
from M import *
dovrebbero utilizzare il__all__
meccanismo per impedire l'esportazione di globi, oppure utilizzare la vecchia convenzione di prefisso tali globi con un carattere di sottolineatura (cosa che potresti voler fare per indicare che questi globi sono "moduli non pubblici").
PEP8 fornisce convenzioni di codifica per il codice Python che comprende la libreria standard nella distribuzione principale di Python. Più segui questo, più sei vicino all'intento originale.
__all__
se__all__
presente, non sono esattamente nascosti; possono essere visti e consultati perfettamente normalmente se conosci i loro nomi. È solo nel caso di un "import *", che comunque non è raccomandato, che la distinzione abbia un peso.