Kann jemand __all__ in Python erklären?

983

Ich benutze Python immer mehr und sehe die Variable immer wieder __all__in verschiedenen __init__.pyDateien. Kann jemand erklären, was das macht?

varikin
quelle

Antworten:

566

Es ist eine Liste der öffentlichen Objekte dieses Moduls, wie von interpretiert import *. Es überschreibt die Standardeinstellung, alles auszublenden, was mit einem Unterstrich beginnt.

Jimmy
quelle
146
Objekte, die mit einem Unterstrich beginnen oder in vorhanden nicht erwähnt __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.
Brandon Rhodes
28
@BrandonRhodes: Das stimmt auch nicht genau: Es wird empfohlen, nur Module zu importieren, für die Sie entwickelt wurden 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.
fliegende Schafe
12
Öffentliche und interne Schnittstellen - python.org/dev/peps/pep-0008/#id50 , Um die Selbstbeobachtung besser zu unterstützen, sollten Module die Namen in ihrer öffentlichen API explizit mit dem Attribut __all__ deklarieren. Wenn Sie __all__ auf eine leere Liste setzen, bedeutet dies, dass das Modul keine öffentliche API hat.
Debug
Ich bin mir nicht sicher, ob tkdie 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.
Chepner
Wie BrandonRhodes betont, ist dies wirklich nicht korrekt
duhaime
947

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.pyexportiert beispielsweise explizit die Symbole barund 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>.

Alec Thomas
quelle
1
sollten wir nicht baz als drucken print(baz())?
John Cole
@ JohnCole baz ist ein Funktionsobjekt und baz () führt das Funktionsobjekt aus
Bhanu Tez
@BhanuTez genau. So print(baz)druckt etwas wie <function baz at 0x7f32bc363c10>während print(baz())Druckebaz
John Cole
223

__All__ in Python erklären?

Ich sehe die Variable immer wieder __all__in verschiedenen __init__.pyDateien.

Was macht das?

Was macht __all__das

Es 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

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

Aus den Dokumenten :

Die __init__.pyDateien 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__.pykann 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__.pykann 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__.pyDatei 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 packageNamespace 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__.pys 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, Bazin der API der obersten Ebene zu veröffentlichen , können Sie in Ihrer obersten Ebene __init__.pyFolgendes 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 Bazes zur Hauptsendezeit bereit ist:

from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']

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

Beim Vermeiden __all__macht Sinn

Es ist sinnvoll, sich an die _Präfixkonvention zu halten, anstatt __all__wann:

  • Sie befinden sich noch im frühen Entwicklungsmodus und haben keine Benutzer. Sie optimieren ständig Ihre API.
  • Möglicherweise haben Sie Benutzer, aber Sie haben Unittests, die die API abdecken, und Sie fügen der API immer noch aktiv hinzu und optimieren die Entwicklung.

Ein exportDekorateur

Der 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
Aaron Hall
quelle
1
Querverweis: Ich habe Ihren Dekorateur in dieser CW-Antwort auf die Frage erwähnt, wie man einen @exportDekorateur schreibt .
MvG
13
Dies hat im Alleingang, die am nützlichsten Antwort , die ich in Bezug gesehen ein relativ neuer Python - Entwickler zu helfen , den Prozesses der Import - Module / Pakete mit Verständnis __init__.pyund die Verwendung von__all__
Brett Reinhard
Das hilft mir sehr. Mein Problem ist jedoch, dass die Submodule, die ich importieren möchte, alle generierten Dateien mit viel Cruft in ihren Symbolen sind, die ich entfernen möchte, ohne manuell sicherstellen zu müssen, dass dies __all__korrekt ist.
Mike C
@MikeC dann sollten Sie vielleicht auch Ihre generieren __all__- aber dann würde ich sagen, Sie haben eine instabile API ... Dies wäre etwas, um einige umfassende Abnahmetests durchzuführen.
Aaron Hall
@AaronHall "Sie werden nicht alle anderen Namen haben ... den Paket-Namespace überladen" Aber sie werden die Namen haben module_1und module_2; Ist es in Ordnung, ein explizites del module_1in aufzunehmen __init__.py? Bin ich falsch zu denken, dass sich das lohnt?
Mike C
176

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__.pyDateien explizit erwähnt , es handelt sich also um Python- Pakete .

Im Allgemeinen kommt __all__nur ins Spiel, wenn die from xxx import *Variante der importAnweisung 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__.pyfrom package import *

Wenn Sie dagegen __all__in einem Modul weglassen , importiert der "markierte Import" alle im Modul definierten Namen (nicht beginnend mit einem Unterstrich).

MartinStettner
quelle
29
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.
Nikratio
Wenn alles [foo, bar] und in der Datei test.py enthält, wenn wir Folgendes verwenden: aus dem Paketimport *, werden foo und bar dann in den lokalen Namespace von test.py oder in den eigenen Namespace foo and bar importiert?
Variable
87

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.

L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
quelle
54

__all__passt *in anfrom <module> import *

__all__passt *in anfrom <package> import *


Ein Modul ist eine .pyDatei, die importiert werden soll.

Ein Paket ist ein Verzeichnis mit einer __init__.pyDatei. Ein Paket enthält normalerweise Module.


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 ]

vom Modulimport *

Sehen Sie, wie swissund cheddarin 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.


Importe ohne *sind davon nicht betroffen__all__


Modul importieren

>>> import cheese
>>> cheese.swiss, cheese.cheddar, cheese.gouda
(4.99, 3.99, 10.99)

von Modul Import Namen

>>> from cheese import swiss, cheddar, gouda
>>> swiss, cheddar, gouda
(4.99, 3.99, 10.99)

Importmodul als lokaler Name

>>> import cheese as ch
>>> ch.swiss, ch.cheddar, ch.gouda
(4.99, 3.99, 10.99)

PAKETE

In der __init__.pyDatei 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__.pyimportiert:

Wenn __all__nicht definiert ist, die Aussage from sound.effects import *ist nicht importiert alle Submodule aus dem Paket sound.effectsin den aktuellen Namensraum; Es wird nur sichergestellt, dass das Paket sound.effectsimportiert 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]

Bob Stein
quelle
2
Ich mag diese Antwort wirklich, aber ich vermisse die Informationen auf , was das Standardverhalten für from <package> import *ohne __all__in __init__.pydas ist nicht der Module zu importieren .
Radzak
Danke @Jatimir, ich habe so gut ich konnte geklärt, ohne Experimente durchzuführen. Ich wollte fast sagen, dass sich dieser Fall (Sternchen ohne alle für ein Paket) genauso verhält wie __init__.pyein 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?
Bob Stein
49

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

Lasse V. Karlsen
quelle
Der aufgelistete Link ist tot. aber Text wörtlich auf vdocuments.net/… & hier gefunden: dokumen.tips/documents/reference-567bab8d6118a.html
JayRizzo
8

__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.pathoder 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__.pyCode eines Pakets eine Liste mit dem Namen definiert __all__, wird dies als Liste der Modulnamen angesehen, die importiert werden sollen, wenn sie from package import *auftreten.

Mihai Capotă
quelle
8

Kurze Antwort

__all__beeinflusst from <module> import *Aussagen.

Lange Antwort

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 .

Cyker
quelle
5

__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 fromAnweisung 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 fooein Attribut vorhanden ist __all__, ist der Wert des Attributs die Liste der Namen, die an diese Art von fromAnweisung gebunden sind .

Wenn fooes sich um ein Paket handelt und __init__.pyeine 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 importAnweisung 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?

Eugene Yarmash
quelle
1

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.

Prosti
quelle