Antworten:
Es ist eine Liste der öffentlichen Objekte dieses Moduls, wie von interpretiert import *
. Es überschreibt die Standardeinstellung, alles auszublenden, was mit einem Unterstrich beginnt.
import *
(z tk
. 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ürde from 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, wenn from <module> import *
sie für das Modul verwendet werden.
Der folgende Code foo.py
exportiert beispielsweise explizit die Symbole bar
und baz
:
__all__ = ['bar', 'baz']
waz = 5
bar = 10
def baz(): return 'baz'
Diese Symbole können dann folgendermaßen importiert werden:
from foo import *
print(bar)
print(baz)
# The following will trigger an exception, as "waz" is not exported by the module
print(waz)
Wenn das __all__
oben Gesagte auskommentiert ist, wird dieser Code vollständig ausgeführt, da standardmäßig import *
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 das from <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 werden from <module> import <member>
.
print(baz())
?
print(baz)
druckt etwas wie <function baz at 0x7f32bc363c10>
während print(baz())
Druckebaz
__All__ in Python erklären?
Ich sehe die Variable immer wieder
__all__
in verschiedenen__init__.py
Dateien.Was macht das?
__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, zB module.py
:
__all__ = ['foo', 'Bar']
bedeutet, dass beim Verlassen import *
des Moduls nur die Namen in das __all__
importiert werden:
from module import * # imports foo and Bar
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 :
Die
__init__.py
Dateien sind erforderlich, damit Python die Verzeichnisse als Pakete enthaltend behandelt. Auf diese Weise wird verhindert, dass Verzeichnisse mit einem allgemeinen Namen, z. B. eine Zeichenfolge, unbeabsichtigt gültige Module ausblenden, die später im Modul-Suchpfad auftreten.Im einfachsten Fall
__init__.py
kann es sich nur um eine leere Datei handeln, es kann jedoch auch Initialisierungscode für das Paket ausgeführt oder die__all__
Variable festgelegt werden.
So __init__.py
kann man das __all__
für ein Paket deklarieren .
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:
package
├── __init__.py
├── module_1.py
└── module_2.py
Lassen Sie uns diese Dateien mit Python erstellen, damit Sie mitmachen können - Sie können Folgendes in eine Python 3-Shell einfügen:
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
""")
Und jetzt haben Sie eine vollständige API präsentiert, die jemand anderes verwenden kann, wenn er Ihr Paket importiert, wie folgt:
import package
package.foo()
package.Bar()
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:
package
├── __init__.py
├── module_1
│ ├── foo_implementation.py
│ └── __init__.py
└── module_2
├── Bar_implementation.py
└── __init__.py
Erstellen Sie zunächst die Unterpaketverzeichnisse mit denselben Namen wie die Module:
subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()
Verschieben Sie die Implementierungen:
package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')
Erstellen Sie __init__.py
s für die Unterpakete, die das __all__
für jedes deklarieren :
(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")
Und jetzt haben Sie immer noch die API auf Paketebene bereitgestellt:
>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>
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:
from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']
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:
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
und wenn Ihre Benutzer die Verfügbarkeit von kennen Baz
, können sie diese verwenden:
import package
package.Baz()
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:
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
_
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 in ctypes/__init__.py
:
import os as _os, sys as _sys
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__
.
__all__
macht SinnEs ist sinnvoll, sich an die _
Präfixkonvention zu halten, anstatt __all__
wann:
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:
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
und dann, wo Sie ein definieren würden __all__
, tun Sie dies:
$ 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()
Und dies funktioniert gut, egal ob als Hauptfunktion ausgeführt oder von einer anderen Funktion importiert.
$ cat > run.py
import main
main.main()
$ python run.py
main
Und die API-Bereitstellung mit import *
funktioniert auch:
$ 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
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
und module_2
; Ist es in Ordnung, ein explizites del 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 die from xxx import *
Variante der import
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 verwenden from 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).
from package import *
importiert weiterhin alles __init__.py
, was in definiert ist , auch wenn es keine gibt all
. 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
a = "A"
b = "B"
c = "C"
module2.py
__all__ = ['a', 'b']
a = "A"
b = "B"
c = "C"
$ pydoc module1
Hilfe zum Modul Modul1: NAME Modul 1 DATEI module1.py DATEN a = 'A' b = 'B' c = 'C'
$ pydoc module2
Hilfe zum Modul Modul2: NAME Modul2 DATEI module2.py DATA __all__ = ['a', 'b'] a = 'A' b = 'B'
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.
__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.
""" cheese.py - an example module """
__all__ = ['swiss', 'cheddar']
swiss = 4.99
cheddar = 3.99
gouda = 10.99
__all__
informiert den Menschen über die "öffentlichen" Funktionen eines Moduls . [ @AaronHall ] Außerdem erkennt pydoc sie. [ @Longpoke ]
Sehen Sie, wie swiss
und cheddar
in den lokalen Namespace gebracht werden, aber nicht 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
Ohne wäre __all__
jedes Symbol (das nicht mit einem Unterstrich beginnt) verfügbar gewesen.
*
sind davon nicht betroffen__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)
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
:
__all__ = [
'MySQLConnection', 'Connect', 'custom_error_exception',
# Some useful constants
'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
'HAVE_CEXT',
# Error handling
'Error', 'Warning',
...etc...
]
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:
Wenn
__all__
nicht definiert ist, die Aussagefrom sound.effects import *
ist nicht importiert alle Submodule aus dem Paketsound.effects
in den aktuellen Namensraum; Es wird nur sichergestellt, dass das Paketsound.effects
importiert wurde (möglicherweise wird ein Initialisierungscode ausgeführt__init__.py
), und anschließend werden alle im Paket definierten Namen importiert. Dies schließt alle Namen ein, die von (und explizit geladene Submodule) definiert wurden__init__.py
. Es enthält auch alle Submodule des Pakets, die von früheren Importanweisungen explizit geladen wurden.
Wildcard-Importe ... sollten vermieden werden, da sie Leser und viele automatisierte Tools [verwirren].
[ PEP 8 , @ToolmakerSteve]
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 :
Die von einem Modul definierten öffentlichen Namen werden ermittelt, indem der Namespace des Moduls auf eine Variable mit dem Namen überprüft wird
__all__
. Wenn definiert, muss es sich um eine Folge von Zeichenfolgen handeln, bei denen es sich um Namen handelt, die von diesem Modul definiert oder importiert wurden. Die in angegebenen Namen__all__
gelten alle als öffentlich und müssen existieren. Wenn__all__
nicht definiert, enthält der Satz öffentlicher Namen alle Namen, die im Namespace des Moduls gefunden wurden und nicht mit einem Unterstrich ("_") beginnen.__all__
sollte die gesamte öffentliche API enthalten. Es soll vermieden werden, dass versehentlich Elemente exportiert werden, die nicht Teil der API sind (z. B. Bibliotheksmodule, die innerhalb des Moduls importiert und verwendet wurden).
__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 :
Die von einem Modul definierten öffentlichen Namen werden ermittelt, indem der Namespace des Moduls auf eine Variable mit dem Namen überprüft wird
__all__
. Wenn definiert, muss es sich um eine Folge von Zeichenfolgen handeln, bei denen es sich um Namen handelt, die von diesem Modul definiert oder importiert wurden. Die in angegebenen Namen__all__
gelten alle als öffentlich und müssen existieren. Wenn__all__
nicht definiert, enthält der Satz öffentlicher Namen alle Namen, die im Namespace des Moduls gefunden wurden und nicht mit einem Unterstrich ('_') beginnen.__all__
sollte die gesamte öffentliche API enthalten. Es soll vermieden werden, dass versehentlich Elemente exportiert werden, die nicht Teil der API sind (z. B. Bibliotheksmodule, die innerhalb des Moduls importiert und verwendet wurden).
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:
Um die Selbstbeobachtung besser zu unterstützen, sollten Module die Namen in ihrer öffentlichen API mithilfe des
__all__
Attributs explizit deklarieren . Das Festlegen__all__
einer leeren Liste zeigt an, dass das Modul keine öffentliche API hat.[...]
Importierte Namen sollten immer als Implementierungsdetail betrachtet werden. Andere Module dürfen nicht auf den indirekten Zugriff auf solche importierten Namen angewiesen sein, es sei denn, sie sind ein explizit dokumentierter Teil der API des enthaltenen Moduls, z. B.
os.path
oder das__init__
Modul eines Pakets , das Funktionen von Submodulen verfügbar macht.
Darüber hinaus wird, wie in anderen Antworten ausgeführt, __all__
der Wildcard-Import für Pakete aktiviert :
Die import-Anweisung verwendet die folgende Konvention: Wenn der
__init__.py
Code eines Pakets eine Liste mit dem Namen definiert__all__
, wird dies als Liste der Modulnamen angesehen, die importiert werden sollen, wenn siefrom package import *
auftreten.
__all__
beeinflusst from <module> import *
Aussagen.
Betrachten Sie dieses Beispiel:
foo
├── bar.py
└── __init__.py
In foo/__init__.py
:
(Implizit) Wenn wir nicht definieren __all__
, from foo import *
werden nur die in definierten Namen importiert foo/__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 .
__all__
beeinflusst, wie from foo import *
funktioniert.
Code, der sich in einem Modulkörper befindet (aber nicht im Körper einer Funktion oder Klasse), kann *
in einer from
Anweisung ein Sternchen ( ) verwenden :
from foo import *
Die *
Anforderungen, dass alle Attribute des Moduls foo
(mit Ausnahme derjenigen, die mit Unterstrichen beginnen) als globale Variablen im importierenden Modul gebunden werden. Wenn foo
ein Attribut vorhanden ist __all__
, ist der Wert des Attributs die Liste der Namen, die an diese Art von from
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 sie from 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 der import
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:
__all__ = ('some_name',)
Siehe auch Warum ist "Import *" schlecht?
Dies ist in PEP8 hier definiert :
Globale Variablennamen
(Hoffen wir, dass diese Variablen nur für die Verwendung innerhalb eines Moduls bestimmt sind.) Die Konventionen entsprechen in etwa denen für Funktionen.
Module, die für die Verwendung über entwickelt wurden,
from M import *
sollten den__all__
Mechanismus verwenden, um das Exportieren von Globals zu verhindern, oder die ältere Konvention verwenden, solchen Globals einen Unterstrich voranzustellen (was Sie möglicherweise tun möchten, um anzuzeigen, dass diese Globals "nicht öffentlich" sind).
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.
__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.