Odpowiedzi:
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.
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.
tk
został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.
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.py
jawnie eksportuje symbole bar
i 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>
.
print(baz())
?
print(baz)
drukuje coś podobnego, <function baz at 0x7f32bc363c10>
podczas gdy print(baz())
drukujebaz
Wyjaśnij __all__ w Pythonie?
Wciąż widzę zmienną
__all__
ustawioną w różnych__init__.py
plikach.Co to robi?
__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 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 PythonaZ dokumentów :
Te
__init__.py
pliki 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__.py
może być tylko pustym plikiem, ale może również wykonać kod inicjujący pakiet lub ustawić__all__
zmienną.
Więc __init__.py
może zadeklarować __all__
na opakowaniu .
Pakiet zazwyczaj składa się z modułów, które mogą się importować, ale które są koniecznie powiązane z __init__.py
plikiem. 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 package
przestrzeń 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__.py
s 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 Baz
w interfejsie API najwyższego poziomu, na najwyższym poziomie __init__.py
moż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 Baz
będzie gotowa na pierwszą porę:
from .module_1 import *
from .module_2 import *
__all__ = ['foo', 'Bar', 'Baz']
_
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__
.
__all__
ma sensSensowne jest trzymanie się _
konwencji prefiksów zamiast, __all__
gdy:
export
dekoratorWadą 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
@export
dekoratora.
__init__.py
i korzystania z__all__
__all__
poprawności.
__all__
- ale wtedy powiedziałbym, że masz niestabilny API ... To byłoby coś, co wymagałoby kompleksowych testów akceptacyjnych.
module_1
i module_2
; Jest to OK, aby zawierać wyraźną del module_1
in __init__.py
? Czy mylę się sądząc, że warto?
Po prostu dodaję to dla ścisłości:
Wszystkie pozostałe odpowiedzi dotyczą modułów . Oryginalne pytanie wyraźnie wymienione __all__
w __init__.py
plikach, więc chodzi o pakiety python .
Zasadniczo __all__
wchodzi w grę tylko wtedy, gdy używany jest from xxx import *
wariant import
instrukcji. 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.
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.
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.
__all__
dostosowuje *
wfrom <module> import *
__all__
dostosowuje *
wfrom <package> import *
Moduł jest .py
plik ma być importowany.
Pakiet jest katalogiem z __init__.py
pliku. Pakiet zwykle zawiera 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 ]
Zobacz, jak swiss
i cheddar
są 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).
*
nie ma wpływu__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)
W __init__.py
pliku 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__.py
importowane są tylko obiekty zdefiniowane w :
Jeśli
__all__
nie jest określony, oświadczeniefrom sound.effects import *
ma nie importować wszystkie submodules z pakietusound.effects
do bieżącej przestrzeni nazw; zapewnia tylko, że pakietsound.effects
został 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]
from <package> import *
nie __all__
w __init__.py
który jest nie lada importowania modułów .
__init__.py
był 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?
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).
__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.path
czy 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__.py
kod pakietu definiuje nazwaną listę__all__
, przyjmuje się, że jest to lista nazw modułów, które należy zaimportować pofrom package import *
napotkaniu.
__all__
wpływa na from <module> import *
stwierdzenia.
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 .
__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 from
instrukcji:
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 foo
ma atrybut __all__
, wartością atrybutu jest lista nazw powiązanych tym typem from
instrukcji.
Jeśli foo
jest to pakiet i jego __init__.py
definiuje 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ą import
instrukcji , 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?
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.
__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ę.