Ich benutze Python immer mehr und sehe die Variable immer wieder __all__
in verschiedenen __init__.py
Dateien. Kann jemand erklären, was das macht?
python
syntax
namespaces
varikin
quelle
quelle
__all__
werden__all__
, sind nicht genau ausgeblendet. Sie können ganz normal gesehen und abgerufen werden, wenn Sie ihre Namen kennen. Nur bei einem "Import *", der ohnehin nicht empfohlen wird, hat die Unterscheidung ein Gewicht.import *
(ztk
. B. ). Ein guter Hinweis, wenn dies der Fall ist, ist das Vorhandensein von__all__
oder Namen, die mit dem Unterstrich im Code des Moduls beginnen.tk
die empfohlene Vorgehensweise wäre , wenn sie heute (oder sogar 2012) veröffentlicht würdefrom tk import *
. Ich denke, die Praxis wird aufgrund der Trägheit akzeptiert, nicht aufgrund des absichtlichen Designs.Verbunden mit, aber hier nicht explizit erwähnt, ist genau wann
__all__
verwendet wird. Es ist eine Liste von Zeichenfolgen, die definieren, welche Symbole in einem Modul exportiert werden, wennfrom <module> import *
sie für das Modul verwendet werden.Der folgende Code
foo.py
exportiert beispielsweise explizit die Symbolebar
undbaz
:Diese Symbole können dann folgendermaßen importiert werden:
Wenn das
__all__
oben Gesagte auskommentiert ist, wird dieser Code vollständig ausgeführt, da standardmäßigimport *
alle Symbole, die nicht mit einem Unterstrich beginnen, aus dem angegebenen Namespace importiert werden.Referenz: https://docs.python.org/tutorial/modules.html#importing-from-a-package
HINWEIS:
__all__
Beeinflusst nur dasfrom <module> import *
Verhalten. Mitglieder, die in nicht erwähnt__all__
sind, sind weiterhin von außerhalb des Moduls zugänglich und können mit importiert werdenfrom <module> import <member>
.quelle
print(baz())
?print(baz)
druckt etwas wie<function baz at 0x7f32bc363c10>
währendprint(baz())
Druckebaz
Was macht
__all__
dasEs deklariert die semantisch "öffentlichen" Namen eines Moduls. Wenn ein Name vorhanden ist
__all__
, wird von den Benutzern erwartet, dass sie ihn verwenden, und sie können davon ausgehen, dass er sich nicht ändert.Es wird auch programmatische Auswirkungen haben:
import *
__all__
in einem Modul, zBmodule.py
:bedeutet, dass beim Verlassen
import *
des Moduls nur die Namen in das__all__
importiert werden:Dokumentationswerkzeuge
Tools für die automatische Vervollständigung von Dokumentationen und Code können (sollten) auch die überprüfen,
__all__
um festzustellen, welche Namen von einem Modul als verfügbar angezeigt werden sollen .__init__.py
macht ein Verzeichnis zu einem Python-PaketAus den Dokumenten :
So
__init__.py
kann man das__all__
für ein Paket deklarieren .Verwalten einer API:
Ein Paket besteht normalerweise aus Modulen, die sich gegenseitig importieren können, aber notwendigerweise mit einer
__init__.py
Datei verbunden sind. Diese Datei macht das Verzeichnis zu einem echten Python-Paket. Angenommen, Sie haben die folgenden Dateien in einem Paket:Lassen Sie uns diese Dateien mit Python erstellen, damit Sie mitmachen können - Sie können Folgendes in eine Python 3-Shell einfügen:
Und jetzt haben Sie eine vollständige API präsentiert, die jemand anderes verwenden kann, wenn er Ihr Paket importiert, wie folgt:
Und das Paket enthält nicht alle anderen Implementierungsdetails, die Sie beim Erstellen Ihrer Module verwendet haben, um den
package
Namespace zu überladen.__all__
im__init__.py
Nach mehr Arbeit haben Sie vielleicht entschieden, dass die Module zu groß sind (wie viele tausend Zeilen?) Und aufgeteilt werden müssen. Sie machen also Folgendes:
Erstellen Sie zunächst die Unterpaketverzeichnisse mit denselben Namen wie die Module:
Verschieben Sie die Implementierungen:
Erstellen Sie
__init__.py
s für die Unterpakete, die das__all__
für jedes deklarieren :Und jetzt haben Sie immer noch die API auf Paketebene bereitgestellt:
Und Sie können Ihrer API ganz einfach Dinge hinzufügen, die Sie auf Unterpaketebene anstelle der Modulebene des Unterpakets verwalten können. Wenn Sie der API einen neuen Namen hinzufügen möchten, aktualisieren Sie einfach den
__init__.py
, z. B. in Modul_2:Und wenn Sie nicht bereit sind,
Baz
in der API der obersten Ebene zu veröffentlichen , können Sie in Ihrer obersten Ebene__init__.py
Folgendes haben:und wenn Ihre Benutzer die Verfügbarkeit von kennen
Baz
, können sie diese verwenden:aber wenn sie nichts davon wissen, werden andere Tools (wie pydoc ) sie nicht informieren.
Sie können dies später ändern, wenn
Baz
es zur Hauptsendezeit bereit ist:Präfix
_
versus__all__
:Standardmäßig exportiert Python alle Namen, die nicht mit einem beginnen
_
. Sie sicherlich könnte auf diesem Mechanismus beruhen. Einige Pakete in der Python - Standard - Bibliothek, in der Tat, sie auf diese angewiesen sind , aber so zu tun, sie alias ihre Importe, zum Beispiel inctypes/__init__.py
:Die Verwendung der
_
Konvention kann eleganter sein, da dadurch die Redundanz beim erneuten Benennen der Namen beseitigt wird. Aber es erhöht die Redundanz für Importe (wenn Sie viele davon haben) und es ist leicht zu vergessen, dies konsequent zu tun - und das Letzte, was Sie wollen, ist, dass Sie etwas, das Sie nur als Implementierungsdetail haben wollten, auf unbestimmte Zeit unterstützen müssen weil Sie_
beim Benennen einer Funktion vergessen haben, ein Präfix zu setzen .Ich persönlich schreibe
__all__
früh in meinem Entwicklungslebenszyklus für Module, damit andere, die meinen Code verwenden, wissen, was sie verwenden und was nicht.Die meisten Pakete in der Standardbibliothek verwenden ebenfalls
__all__
.Beim Vermeiden
__all__
macht SinnEs ist sinnvoll, sich an die
_
Präfixkonvention zu halten, anstatt__all__
wann:Ein
export
DekorateurDer Nachteil der Verwendung
__all__
ist, dass Sie die Namen der Funktionen und Klassen, die zweimal exportiert werden, zweimal schreiben müssen - und die Informationen von den Definitionen getrennt bleiben. Wir könnten einen Dekorateur verwenden, um dieses Problem zu lösen.Die Idee für einen solchen Exportdekorateur kam mir aus David Beazleys Vortrag über Verpackung. Diese Implementierung scheint im traditionellen Importeur von CPython gut zu funktionieren. Wenn Sie einen speziellen Import-Hook oder ein System haben, kann ich dies nicht garantieren, aber wenn Sie es übernehmen, ist es ziemlich trivial, zurückzutreten - Sie müssen die Namen nur manuell wieder in das hinzufügen
__all__
In einer Utility-Bibliothek würden Sie beispielsweise den Dekorator definieren:
und dann, wo Sie ein definieren würden
__all__
, tun Sie dies:Und dies funktioniert gut, egal ob als Hauptfunktion ausgeführt oder von einer anderen Funktion importiert.
Und die API-Bereitstellung mit
import *
funktioniert auch:quelle
@export
Dekorateur schreibt .__init__.py
und die Verwendung von__all__
__all__
korrekt ist.__all__
- aber dann würde ich sagen, Sie haben eine instabile API ... Dies wäre etwas, um einige umfassende Abnahmetests durchzuführen.module_1
undmodule_2
; Ist es in Ordnung, ein explizitesdel module_1
in aufzunehmen__init__.py
? Bin ich falsch zu denken, dass sich das lohnt?Ich füge dies nur hinzu, um genau zu sein:
Alle anderen Antworten beziehen sich auf Module . Die ursprüngliche Frage wird
__all__
in__init__.py
Dateien explizit erwähnt , es handelt sich also um Python- Pakete .Im Allgemeinen kommt
__all__
nur ins Spiel, wenn diefrom xxx import *
Variante derimport
Anweisung verwendet wird. Dies gilt sowohl für Pakete als auch für Module.Das Verhalten für Module wird in den anderen Antworten erläutert. Das genaue Verhalten für Pakete wird hier ausführlich beschrieben.
Kurz gesagt,
__all__
auf Paketebene wird ungefähr dasselbe getan wie für Module, außer dass es sich um Module innerhalb des Pakets handelt (im Gegensatz zur Angabe von Namen innerhalb des Moduls ). So__all__
gibt alle Module , die in den aktuellen Namensraum geladen und importiert werden müssen , wenn wir verwendenfrom package import *
.Der große Unterschied besteht darin, dass die Anweisung , wenn Sie die Deklaration in einem Paket weglassen , überhaupt nichts importiert (mit Ausnahmen, die in der Dokumentation erläutert werden, siehe Link oben).
__all__
__init__.py
from package import *
Wenn Sie dagegen
__all__
in einem Modul weglassen , importiert der "markierte Import" alle im Modul definierten Namen (nicht beginnend mit einem Unterstrich).quelle
from package import *
importiert weiterhin alles__init__.py
, was in definiert ist , auch wenn es keine gibtall
. Der wichtige Unterschied besteht darin, dass ohne__all__
sie keine im Paketverzeichnis definierten Module automatisch importiert werden.Es ändert auch, was pydoc zeigen wird:
module1.py
module2.py
$ pydoc module1
$ pydoc module2
Ich erkläre
__all__
in allen meinen Modulen und unterstreiche interne Details. Diese helfen wirklich, wenn Sie Dinge verwenden, die Sie noch nie zuvor in Live-Dolmetschersitzungen verwendet haben.quelle
__all__
passt*
in anfrom <module> import *
__all__
passt*
in anfrom <package> import *
Ein Modul ist eine
.py
Datei, die importiert werden soll.Ein Paket ist ein Verzeichnis mit einer
__init__.py
Datei. Ein Paket enthält normalerweise Module.MODULE
__all__
informiert den Menschen über die "öffentlichen" Funktionen eines Moduls . [ @AaronHall ] Außerdem erkennt pydoc sie. [ @Longpoke ]vom Modulimport *
Sehen Sie, wie
swiss
undcheddar
in den lokalen Namespace gebracht werden, aber nichtgouda
:Ohne wäre
__all__
jedes Symbol (das nicht mit einem Unterstrich beginnt) verfügbar gewesen.Importe ohne
*
sind davon nicht betroffen__all__
Modul importieren
von Modul Import Namen
Importmodul als lokaler Name
PAKETE
In der
__init__.py
Datei eines Pakets__all__
befindet sich eine Liste von Zeichenfolgen mit den Namen öffentlicher Module oder anderer Objekte. Diese Funktionen stehen für Platzhalterimporte zur Verfügung. Passt wie beim Modul__all__
das*
Importieren von Platzhaltern aus dem Paket an. [ @MartinStettner ]Hier ist ein Auszug aus dem Python MySQL Connector
__init__.py
:Der Standardfall, Sternchen ohne Nein
__all__
für ein Paket , ist kompliziert, da das offensichtliche Verhalten teuer wäre: Verwenden des Dateisystems zum Suchen nach allen Modulen im Paket. Stattdessen werden beim Lesen der Dokumente nur die in definierten Objekte__init__.py
importiert:[ PEP 8 , @ToolmakerSteve]
quelle
from <package> import *
ohne__all__
in__init__.py
das ist nicht der Module zu importieren .__init__.py
ein Modul . Ich bin mir jedoch nicht sicher, ob dies korrekt ist oder ob Objekte mit Unterstrichen ausgeschlossen sind. Außerdem habe ich die Abschnitte über MODULE und PAKETE klarer getrennt. Ihre Gedanken?Aus (einem inoffiziellen) Python-Referenz-Wiki :
quelle
__all__
wird verwendet, um die öffentliche API eines Python-Moduls zu dokumentieren. Obwohl es optional ist,__all__
sollte verwendet werden.Hier ist der relevante Auszug aus der Python-Sprachreferenz :
PEP 8 verwendet einen ähnlichen Wortlaut, macht jedoch auch deutlich, dass importierte Namen nicht Teil der öffentlichen API sind, wenn sie nicht
__all__
vorhanden sind:Darüber hinaus wird, wie in anderen Antworten ausgeführt,
__all__
der Wildcard-Import für Pakete aktiviert :quelle
Kurze Antwort
__all__
beeinflusstfrom <module> import *
Aussagen.Lange Antwort
Betrachten Sie dieses Beispiel:
In
foo/__init__.py
:(Implizit) Wenn wir nicht definieren
__all__
,from foo import *
werden nur die in definierten Namen importiertfoo/__init__.py
.(Explizit) Wenn wir definieren
__all__ = []
,from foo import *
wird nichts importiert.(Explizit) Wenn wir definieren
__all__ = [ <name1>, ... ]
,from foo import *
werden nur diese Namen importiert.Beachten Sie, dass Python im impliziten Fall keine Namen importiert, die mit beginnen
_
. Sie können jedoch den Import solcher Namen mit erzwingen__all__
.Sie können das Python-Dokument hier anzeigen .
quelle
__all__
beeinflusst, wiefrom foo import *
funktioniert.Code, der sich in einem Modulkörper befindet (aber nicht im Körper einer Funktion oder Klasse), kann
*
in einerfrom
Anweisung ein Sternchen ( ) verwenden :Die
*
Anforderungen, dass alle Attribute des Modulsfoo
(mit Ausnahme derjenigen, die mit Unterstrichen beginnen) als globale Variablen im importierenden Modul gebunden werden. Wennfoo
ein Attribut vorhanden ist__all__
, ist der Wert des Attributs die Liste der Namen, die an diese Art vonfrom
Anweisung gebunden sind .Wenn
foo
es sich um ein Paket handelt und__init__.py
eine Liste mit dem Namen definiert__all__
, wird davon ausgegangen, dass es sich um die Liste der Submodulnamen handelt, die importiert werden sollen, wenn siefrom foo import *
auftreten. Wenn__all__
nicht definiert,from foo import *
importiert die Anweisung alle Namen, die im Paket definiert sind. Dies schließt alle Namen ein, die von (und explizit geladene Submodule) definiert wurden__init__.py
.Beachten Sie, dass
__all__
dies keine Liste sein muss. Gemäß der Dokumentation in derimport
Anweisung muss , falls definiert,__all__
eine Folge von Zeichenfolgen sein, deren Namen vom Modul definiert oder importiert werden. Sie können also auch ein Tupel verwenden, um Speicher- und CPU-Zyklen zu sparen . Vergessen Sie nur nicht ein Komma, falls das Modul einen einzelnen öffentlichen Namen definiert:Siehe auch Warum ist "Import *" schlecht?
quelle
Dies ist in PEP8 hier definiert :
PEP8 bietet Codierungskonventionen für den Python-Code, der die Standardbibliothek in der Haupt-Python-Distribution enthält. Je mehr Sie dem folgen, desto näher sind Sie der ursprünglichen Absicht.
quelle