Czy ktoś może wyjaśnić __all__ w Pythonie?

982

Coraz częściej używam Pythona i ciągle widzę zmienną __all__ustawioną w różnych __init__.pyplikach. Czy ktoś może wyjaśnić, co to robi?

varikin
źródło

Odpowiedzi:

565

Jest to lista obiektów publicznych tego modułu, zgodnie z interpretacją import *. Zastępuje domyślne ukrywanie wszystkiego, co zaczyna się od znaku podkreślenia.

Jimmy
źródło
146
Obiekty, które zaczynają się znakiem podkreślenia lub nie są wymienione w, __all__jeśli __all__jest obecny, nie są dokładnie ukryte; można je zobaczyć i uzyskać do nich dostęp normalnie, jeśli znasz ich nazwiska. Jedynie w przypadku „importu”, który i tak nie jest zalecany, rozróżnienie ma jakąkolwiek wagę.
Brandon Rhodes,
28
@BrandonRhodes: to też nie do końca prawda: zalecane jest importowanie tylko modułów, dla których wiesz, że są przeznaczone import *(np tk.). Dobrą wskazówką, jeśli tak jest, jest obecność __all__lub nazwy zaczynające się od podkreślenia w kodzie modułu.
latające owce
12
Interfejsy publiczne i wewnętrzne - python.org/dev/peps/pep-0008/#id50 , Aby lepiej obsługiwać introspekcję, moduły powinny jawnie deklarować nazwy w swoim publicznym interfejsie API za pomocą atrybutu __all__. Ustawienie __all__ na pustą listę wskazuje, że moduł nie ma publicznego API.
debuguj
Nie jestem pewien, czy gdyby tkzostały wydane dzisiaj (a nawet w 2012 r.), Zalecaną praktyką byłoby użycie from tk import *. Myślę, że praktyka jest akceptowana z powodu bezwładności, a nie zamierzonego projektu.
chepner,
Jak zauważa BrandonRhodes, to naprawdę nie jest poprawne
duhaime
947

Połączony z, ale nie wymieniony tutaj wyraźnie, jest dokładnie wtedy, gdy __all__jest używany. Jest to lista ciągów znaków określających, które symbole w module zostaną wyeksportowane, gdy from <module> import *zostaną użyte w module.

Na przykład poniższy kod foo.pyjawnie eksportuje symbole bari baz:

__all__ = ['bar', 'baz']

waz = 5
bar = 10
def baz(): return 'baz'

Te symbole można następnie zaimportować w następujący sposób:

from foo import *

print(bar)
print(baz)

# The following will trigger an exception, as "waz" is not exported by the module
print(waz)

Jeśli __all__powyższe zostanie skomentowane, kod ten zostanie wykonany do końca, ponieważ domyślnym zachowaniem import *jest importowanie wszystkich symboli, które nie zaczynają się znakiem podkreślenia, z podanej przestrzeni nazw.

Odniesienie: https://docs.python.org/tutorial/modules.html#importing-from-a-package

UWAGA: __all__ wpływa from <module> import *tylko na zachowanie. Elementy niewymienione w __all__są nadal dostępne spoza modułu i można je importować za pomocą from <module> import <member>.

Alec Thomas
źródło
1
nie powinniśmy drukować baz jako print(baz())?
John Cole
@JohnCole baz jest obiektem funkcji, a baz () uruchomi obiekt funkcji
Bhanu Tez
@BhanuTez dokładnie. Więc print(baz)drukuje coś podobnego, <function baz at 0x7f32bc363c10>podczas gdy print(baz())drukujebaz
John Cole
223

Wyjaśnij __all__ w Pythonie?

Wciąż widzę zmienną __all__ustawioną w różnych __init__.pyplikach.

Co to robi?

Co ma __all__zrobić?

Deklaruje semantycznie „publiczne” nazwy z modułu. Jeśli istnieje nazwa __all__, użytkownicy powinni z niej korzystać i mogą oczekiwać, że się nie zmieni.

Będzie także miał wpływ programowy:

import *

__all__w module, np . module.py:

__all__ = ['foo', 'Bar']

oznacza, że ​​gdy jesteś import *z modułu, __all__importowane są tylko te nazwy z :

from module import *               # imports foo and Bar

Narzędzia dokumentacji

Narzędzia do autouzupełniania dokumentacji i kodu mogą (a nawet powinny) sprawdzać także, __all__jakie nazwy mają być wyświetlane jako dostępne z modułu.

__init__.py zamienia katalog w pakiet Pythona

Z dokumentów :

Te __init__.pypliki są wymagane, aby Pythona traktować jak katalogi zawierające pakiety; Ma to na celu zapobieganie przypadkowemu ukrywaniu prawidłowych modułów pojawiających się później na ścieżce wyszukiwania modułów w katalogach o wspólnej nazwie, takich jak łańcuch.

W najprostszym przypadku __init__.pymoże być tylko pustym plikiem, ale może również wykonać kod inicjujący pakiet lub ustawić __all__zmienną.

Więc __init__.pymoże zadeklarować __all__na opakowaniu .

Zarządzanie interfejsem API:

Pakiet zazwyczaj składa się z modułów, które mogą się importować, ale które są koniecznie powiązane z __init__.pyplikiem. Ten plik sprawia, że ​​katalog jest rzeczywistym pakietem Pythona. Załóżmy na przykład, że masz w pakiecie następujące pliki:

package
├── __init__.py
├── module_1.py
└── module_2.py

Utwórzmy te pliki za pomocą Pythona, abyś mógł śledzić - możesz wkleić następujące elementy do powłoki 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
""")

A teraz przedstawiłeś kompletny interfejs API, którego może użyć ktoś inny podczas importowania Twojego pakietu, na przykład:

import package
package.foo()
package.Bar()

A pakiet nie będzie zawierał wszystkich innych szczegółów implementacji użytych podczas tworzenia modułów zaśmiecających packageprzestrzeń nazw.

__all__ w __init__.py

Po dłuższej pracy może zdecydowałeś, że moduły są zbyt duże (jak wiele tysięcy linii?) I trzeba je rozdzielić. Więc wykonaj następujące czynności:

package
├── __init__.py
├── module_1
│   ├── foo_implementation.py
│   └── __init__.py
└── module_2
    ├── Bar_implementation.py
    └── __init__.py

Najpierw utwórz katalogi podpakietowe o takich samych nazwach jak moduły:

subpackage_1 = package / 'module_1'
subpackage_1.mkdir()
subpackage_2 = package / 'module_2'
subpackage_2.mkdir()

Przenieś implementacje:

package_module_1.rename(subpackage_1 / 'foo_implementation.py')
package_module_2.rename(subpackage_2 / 'Bar_implementation.py')

utwórz __init__.pys dla podpakietów, które deklarują __all__dla każdego:

(subpackage_1 / '__init__.py').write_text("""
from .foo_implementation import *
__all__ = ['foo']
""")
(subpackage_2 / '__init__.py').write_text("""
from .Bar_implementation import *
__all__ = ['Bar']
""")

A teraz masz api aprowizowany na poziomie pakietu:

>>> import package
>>> package.foo()
>>> package.Bar()
<package.module_2.Bar_implementation.Bar object at 0x7f0c2349d210>

I możesz łatwo dodawać do swojego API elementy, którymi możesz zarządzać na poziomie podpakietu zamiast na poziomie modułu podpakietu. Jeśli chcesz dodać nową nazwę do API, po prostu zaktualizuj __init__.py, np. W module_2:

from .Bar_implementation import *
from .Baz_implementation import *
__all__ = ['Bar', 'Baz']

A jeśli nie jesteś gotowy do publikowania Bazw interfejsie API najwyższego poziomu, na najwyższym poziomie __init__.pymożesz mieć:

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

a jeśli użytkownicy wiedzą o dostępności Baz, mogą z niej skorzystać:

import package
package.Baz()

ale jeśli nie wiedzą o tym, inne narzędzia (takie jak pydoc ) ich nie poinformują.

Możesz później zmienić tę opcję, gdy Bazbędzie gotowa na pierwszą porę:

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

Prefiks _a __all__:

Domyślnie Python eksportuje wszystkie nazwy, które nie zaczynają się od _. Z pewnością mogłoby polegać na tym mechanizmie. Niektóre pakiety w standardowej biblioteki Pythona, w rzeczywistości, ma polegać na tym, ale aby to zrobić, oni alias ich importu, na przykład w ctypes/__init__.py:

import os as _os, sys as _sys

Korzystanie z _konwencji może być bardziej eleganckie, ponieważ usuwa zbędne nazewnictwo nazw ponownie. Ale dodaje redundancji dla importów (jeśli masz ich dużo) i łatwo jest zapomnieć o tym, aby robić to konsekwentnie - a ostatnią rzeczą, jakiej chcesz, jest konieczność bezterminowego wspierania czegoś, co chciałeś być jedynie szczegółem implementacji, po prostu ponieważ zapomniałeś prefiksu _podczas nazywania funkcji.

Osobiście piszę na __all__początku mojego cyklu rozwoju modułów, aby inni, którzy mogą używać mojego kodu, wiedzieli, czego powinni używać, a czego nie.

Większość pakietów w standardowej bibliotece również używa __all__.

Kiedy unikanie __all__ma sens

Sensowne jest trzymanie się _konwencji prefiksów zamiast, __all__gdy:

  • Nadal jesteś w trybie wczesnego programowania i nie masz użytkowników, a także ciągle poprawiasz interfejs API.
  • Być może masz użytkowników, ale masz unittests, które obejmują API, i nadal aktywnie dodajesz do API i dostosowujesz w fazie rozwoju.

exportdekorator

Wadą używania __all__jest to, że musisz wpisać nazwy funkcji i klas eksportowanych dwukrotnie - a informacje są oddzielone od definicji. My mogliśmy użyć dekorator, aby rozwiązać ten problem.

Pomysł na takiego dekoratora eksportu wpadłem na pomysł Davida Beazleya na temat opakowań. Ta implementacja wydaje się działać dobrze w tradycyjnym importerze CPython. Jeśli masz specjalny hak lub system importu, nie gwarantuję go, ale jeśli go zastosujesz, wycofanie się z niego jest dość banalne - wystarczy ręcznie dodać nazwy z powrotem do__all__

Na przykład w bibliotece narzędziowej można zdefiniować dekorator:

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

a następnie, tam gdzie byś zdefiniował __all__, robisz to:

$ 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()

I to działa dobrze, niezależnie od tego, czy jest uruchamiane jako główne, czy importowane przez inną funkcję.

$ cat > run.py
import main
main.main()

$ python run.py
main

A obsługa interfejsu API również import *będzie działać:

$ 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
źródło
1
Odsyłacz: Wspomniałem o twoim dekoratorze w tej odpowiedzi CW na pytanie, jak napisać @exportdekoratora.
MvG
13
Jest to jedna z najbardziej pomocnych odpowiedzi, jakie widziałem w odniesieniu do pomocy stosunkowo nowemu deweloperowi języka Python w zrozumieniu procesu importowania modułów / pakietów __init__.pyi korzystania z__all__
Brett Reinhard
To mi bardzo pomaga. Mój problem polega na tym, że wszystkie podmoduły, które chcę zaimportować, to wygenerowane pliki z dużą ilością cruftu w swoich symbolach, które chciałbym usunąć, bez konieczności ręcznego sprawdzania __all__poprawności.
Mike C
@MikeC to może ty też powinieneś wygenerować __all__- ale wtedy powiedziałbym, że masz niestabilny API ... To byłoby coś, co wymagałoby kompleksowych testów akceptacyjnych.
Aaron Hall
@AaronHall "nie będą mieli wszystkich innych nazw ... zaśmiecają przestrzeń nazw pakietów" Ale będą mieli nazwy module_1i module_2; Jest to OK, aby zawierać wyraźną del module_1in __init__.py? Czy mylę się sądząc, że warto?
Mike C
176

Po prostu dodaję to dla ścisłości:

Wszystkie pozostałe odpowiedzi dotyczą modułów . Oryginalne pytanie wyraźnie wymienione __all__w __init__.pyplikach, więc chodzi o pakiety python .

Zasadniczo __all__wchodzi w grę tylko wtedy, gdy używany jest from xxx import *wariant importinstrukcji. Dotyczy to zarówno pakietów, jak i modułów.

Zachowanie modułów wyjaśniono w innych odpowiedziach. Dokładne zachowanie pakietów opisano tutaj szczegółowo.

Krótko mówiąc, __all__na poziomie pakietu robi mniej więcej to samo, co w przypadku modułów, z tym że zajmuje się modułami w pakiecie (w przeciwieństwie do określania nazw w module ). __all__Określa więc wszystkie moduły, które zostaną załadowane i zaimportowane do bieżącej przestrzeni nazw, gdy będziemy ich używać from package import *.

Duża różnica polega na tym, że jeśli pominiesz deklarację __all__w pakiecie __init__.py, instrukcja w from package import *ogóle nic nie zaimportuje (z wyjątkami wyjaśnionymi w dokumentacji, patrz link powyżej).

Z drugiej strony, jeśli pominiesz __all__w module, „importowanie z gwiazdką” spowoduje zaimportowanie wszystkich nazw (nie rozpoczynających się znakiem podkreślenia) zdefiniowanych w module.

MartinStettner
źródło
29
from package import *nadal zaimportuje wszystko zdefiniowane w __init__.py, nawet jeśli nie ma all. Ważną różnicą jest to, że bez __all__niego nie będzie automatycznie importować żadnych modułów zdefiniowanych w katalogu pakietu.
Nikratio
Gdy wszystko zawiera [foo, bar] i plik test.py, jeśli użyjemy: z importu pakietu *, to czy foo i bar zostaną zaimportowane w lokalnej przestrzeni nazw test.py czy we własnej przestrzeni nazw foo i bary?
zmienna
87

Zmienia również to, co pokaże pydoc:

moduł1.py

a = "A"
b = "B"
c = "C"

module2.py

__all__ = ['a', 'b']

a = "A"
b = "B"
c = "C"

Moduł $ pydoc 1

Pomoc w module module 1:

IMIĘ
    moduł 1

PLIK
    moduł1.py

DANE 
    a = „A”
     b = „B”
     c = „C”

$ pydoc module2

Pomoc na temat modułu module2:

IMIĘ
    moduł2

PLIK
    module2.py

DANE 
    __all__ = ['a', 'b']
     a = 'A'
     b = 'B'

Deklaruję __all__we wszystkich moich modułach, a także podkreślam szczegóły wewnętrzne, które naprawdę pomagają, gdy używam rzeczy, których nigdy wcześniej nie używałeś podczas sesji tłumacza na żywo.

L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳
źródło
54

__all__dostosowuje *wfrom <module> import *

__all__dostosowuje *wfrom <package> import *


Moduł jest .pyplik ma być importowany.

Pakiet jest katalogiem z __init__.pypliku. Pakiet zwykle zawiera moduły.


MODUŁY

""" cheese.py - an example module """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__pozwala ludziom poznać „publiczne” funkcje modułu . [ @AaronHall ] Również pydoc je rozpoznaje. [ @Longpoke ]

z importu modułu *

Zobacz, jak swissi cheddarsą wprowadzane do lokalnej przestrzeni nazw, ale nie 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

Bez __all__tego byłby dostępny dowolny symbol (który nie zaczyna się od podkreślenia).


Na import bez *nie ma wpływu__all__


moduł importu

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

z nazw importu modułów

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

zaimportuj moduł jako nazwę lokalną

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

PAKIETY

W __init__.pypliku pakietu __all__ znajduje się lista ciągów znaków z nazwami modułów publicznych lub innych obiektów. Te funkcje są dostępne do importowania symboli wieloznacznych. Podobnie jak w przypadku modułów, __all__dostosowuje *przy importowaniu symboli wieloznacznych z pakietu. [ @MartinStettner ]

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

    ]

Domyślny przypadek, gwiazdka bez __all__dla pakietu , jest skomplikowany, ponieważ oczywiste zachowanie byłoby kosztowne: użycie systemu plików do wyszukiwania wszystkich modułów w pakiecie. Zamiast tego podczas czytania dokumentów __init__.pyimportowane są tylko obiekty zdefiniowane w :

Jeśli __all__nie jest określony, oświadczenie from sound.effects import *ma nie importować wszystkie submodules z pakietu sound.effectsdo bieżącej przestrzeni nazw; zapewnia tylko, że pakiet sound.effectszostał zaimportowany (możliwe uruchomienie dowolnego kodu inicjującego __init__.py), a następnie zaimportuje dowolne nazwy zdefiniowane w pakiecie. Obejmuje to wszelkie nazwy zdefiniowane (i jawnie załadowane podmoduły) przez __init__.py. Obejmuje również wszelkie podmoduły pakietu, które zostały jawnie załadowane przez poprzednie instrukcje importu.


Należy unikać importowania symboli wieloznacznych ..., ponieważ [mylą one] czytniki i wiele zautomatyzowanych narzędzi.

[ PEP 8 , @ToolmakerSteve]

Bob Stein
źródło
2
Bardzo podoba mi się ta odpowiedź, ale brakuje mi informacji o tym, co jest domyślne zachowanie za from <package> import *nie __all__w __init__.pyktóry jest nie lada importowania modułów .
radzak
Dzięki @Jatimir, wyjaśniłem najlepiej jak mogłem bez przeprowadzania eksperymentów. Prawie chciałem powiedzieć, że ten przypadek (gwiazdka bez wszystkiego dla pakietu) zachowuje się tak, jakby __init__.pybył modułem . Ale nie jestem pewien, czy to jest dokładne, w szczególności jeśli wykluczone są obiekty z prefiksem podkreślenia. Ponadto jaśniej oddzieliłem sekcje dotyczące MODUŁÓW i PAKIETÓW. Twoje myśli?
Bob Stein
49

Z (Nieoficjalna) Wiki Python Wiki :

Nazwy publiczne zdefiniowane przez moduł są określane przez sprawdzenie przestrzeni nazw modułu pod kątem zmiennej o nazwie __all__; jeśli jest zdefiniowany, musi to być ciąg ciągów, które są nazwami zdefiniowanymi lub importowanymi przez ten moduł. Wszystkie podane nazwiska __all__są uważane za publiczne i muszą istnieć. Jeśli __all__nie jest zdefiniowany, zestaw nazw publicznych obejmuje wszystkie nazwy znalezione w przestrzeni nazw modułu, które nie zaczynają się znakiem podkreślenia („_”). __all__powinien zawierać cały publiczny interfejs API. Ma to na celu uniknięcie przypadkowego eksportowania elementów, które nie są częścią interfejsu API (takich jak moduły biblioteczne, które zostały zaimportowane i użyte w module).

Lasse V. Karlsen
źródło
Podany link nie działa. ale znalazłem tekst dosłownie na vdocuments.net/… i tutaj: dokumen.tips/documents/reference-567bab8d6118a.html
JayRizzo
8

__all__służy do dokumentowania publicznego interfejsu API modułu Python. Chociaż jest to opcjonalne, __all__należy go użyć.

Oto odpowiedni fragment odwołania do języka Python :

Nazwy publiczne zdefiniowane przez moduł są określane przez sprawdzenie przestrzeni nazw modułu pod kątem zmiennej o nazwie __all__; jeśli jest zdefiniowany, musi to być ciąg ciągów, które są nazwami zdefiniowanymi lub importowanymi przez ten moduł. Wszystkie podane nazwiska __all__są uważane za publiczne i muszą istnieć. Jeśli __all__nie jest zdefiniowany, zestaw nazw publicznych obejmuje wszystkie nazwy znalezione w przestrzeni nazw modułu, które nie zaczynają się znakiem podkreślenia („_”). __all__powinien zawierać cały publiczny interfejs API. Ma to na celu uniknięcie przypadkowego eksportowania elementów, które nie są częścią interfejsu API (takich jak moduły biblioteczne, które zostały zaimportowane i użyte w module).

PEP 8 używa podobnego sformułowania, chociaż wyjaśnia również, że zaimportowane nazwy nie są częścią publicznego interfejsu API, gdy __all__jest nieobecny:

Aby lepiej obsługiwać introspekcję, moduły powinny jawnie deklarować nazwy w swoim publicznym interfejsie API za pomocą __all__atrybutu. Ustawienie __all__pustej listy wskazuje, że moduł nie ma publicznego interfejsu API.

[...]

Zaimportowane nazwy należy zawsze traktować jako szczegół implementacji. Inne moduły nie muszą polegać na pośredni dostęp do takich nazw importowanych chyba że są one wyraźnie udokumentowanym częścią modułu zawierającego API, takich jak os.pathczy pakiet jest __init__modułem, który eksponuje funkcjonalność z submodules.

Ponadto, jak wskazano w innych odpowiedziach, __all__umożliwia importowanie symboli wieloznacznych dla pakietów :

Instrukcja importu wykorzystuje następującą konwencję: jeśli __init__.pykod pakietu definiuje nazwaną listę __all__, przyjmuje się, że jest to lista nazw modułów, które należy zaimportować po from package import *napotkaniu.

Mihai Capotă
źródło
8

Krótka odpowiedź

__all__wpływa na from <module> import *stwierdzenia.

Długa odpowiedź

Rozważ ten przykład:

foo
├── bar.py
└── __init__.py

W foo/__init__.py:

  • (Implikowany) Jeśli nie zdefiniujemy __all__, to from foo import *zaimportujemy tylko nazwy zdefiniowane w foo/__init__.py.

  • (Jawne) Jeśli zdefiniujemy __all__ = [], to from foo import *nic nie zaimportujemy.

  • (Jawne) Jeśli zdefiniujemy __all__ = [ <name1>, ... ], wówczas from foo import *zaimportujemy tylko te nazwy.

Zauważ, że w domyślnym przypadku python nie importuje nazw zaczynających się od _. Możesz jednak wymusić importowanie takich nazw przy użyciu __all__.

Można wyświetlić dokument Pythona tutaj .

Cyker
źródło
5

__all__wpływa na to, jak from foo import *działa.

Kod znajdujący się w treści modułu (ale nie w treści funkcji lub klasy) może używać gwiazdki *w frominstrukcji:

from foo import *

Te *wnioski, że wszystkie atrybuty modułu foo(z wyjątkiem początku podkreślenia) jest związany jako zmienne globalne w module przywozu. Gdy fooma atrybut __all__, wartością atrybutu jest lista nazw powiązanych tym typem frominstrukcji.

Jeśli foojest to pakiet i jego __init__.pydefiniuje listę nazwie __all__, to przyjmuje się lista nazw modułem, który powinien być importowane przy from foo import *napotkaniu. Jeśli __all__nie jest zdefiniowane, instrukcja from foo import *importuje dowolne nazwy zdefiniowane w pakiecie. Obejmuje to wszelkie nazwy zdefiniowane (i jawnie załadowane podmoduły) przez __init__.py.

Pamiętaj, że __all__nie musi to być lista. Zgodnie z dokumentacją importinstrukcji , jeśli jest zdefiniowana, __all__musi to być ciąg ciągów, które są nazwami zdefiniowanymi lub zaimportowanymi przez moduł. Więc równie dobrze możesz użyć krotki, aby zaoszczędzić trochę pamięci i cykli procesora. Nie zapomnij o przecinku, jeśli moduł definiuje jedną nazwę publiczną:

__all__ = ('some_name',)

Zobacz także Dlaczego „import *” jest zły?

Eugene Yarmash
źródło
1

Jest to zdefiniowane w PEP8 tutaj :

Globalne nazwy zmiennych

(Miejmy nadzieję, że te zmienne są przeznaczone do użycia tylko w jednym module). Konwencje są mniej więcej takie same jak w przypadku funkcji.

Moduły zaprojektowane do użycia przez from M import *powinny używać __all__mechanizmu zapobiegającego eksportowaniu globałów lub zastosować starszą konwencję poprzedzania takich globałów znakiem podkreślenia (co możesz chcieć zrobić, aby wskazać, że globały te są „modułami niepublicznymi”).

PEP8 zapewnia konwencje kodowania dla kodu Pythona zawierającego standardową bibliotekę w głównej dystrybucji Pythona. Im więcej tego przestrzegasz, tym bardziej zbliżasz się do pierwotnych zamiarów.

prosti
źródło