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.
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.
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>.
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__.pyplikach.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__.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 .
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__.pyPo 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']
_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:
exportdekoratorWadą 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
@exportdekoratora.
__init__.pyi 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_1i module_2; Jest to OK, aby zawierać wyraźną del module_1in __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__.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.
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 .pyplik ma być importowany.
Pakiet jest katalogiem z __init__.pypliku. 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 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).
*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__.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świadczeniefrom sound.effects import *ma nie importować wszystkie submodules z pakietusound.effectsdo bieżącej przestrzeni nazw; zapewnia tylko, że pakietsound.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]
from <package> import *nie __all__w __init__.pyktóry jest nie lada importowania modułów .
__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?
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.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ć 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 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?
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ę.