Kan noen forklare __all__ i Python?

stemmer
639

Jeg har brukt Python mer og mer, og jeg ser den variable __all__sett i forskjellige __init__.pyfiler. Kan noen forklare hva dette betyr?

Publisert på 04/09/2008 klokken 21:28
kilden bruker
På andre språk...                            


11 svar

stemmer
685

Knyttet til, men ikke eksplisitt nevnt her, er nøyaktig når __all__brukes. Det er en liste over strenger som definerer hva som symboler i en modul vil bli eksportert når from <module> import *brukes på modulen.

For eksempel følgende kode i en foo.pyeksplisitt eksporterer symbolene barog baz:

__all__ = ['bar', 'baz']

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

Disse symbolene kan deretter importeres som så:

from foo import *

print bar
print baz

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

Hvis __all__ovenfor er kommentert ut, vil denne koden deretter kjøre til ferdigstillelse, som standard oppførsel import *er å importere alle symboler som ikke begynner med en understrekning, fra den gitte navnerom.

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

MERK: __all__ påvirker from <module> import *bare atferd. Medlemmer som ikke er nevnt i __all__er fortsatt tilgjengelig fra utsiden av modulen og kan importeres med from <module> import <member>.

Svarte 15/09/2008 kl. 15:49
kilden bruker

stemmer
323

Det er en liste over offentlige objekter av den modulen, som tolket av import *. Det overstyrer standard skjule alt som begynner med en understrek.

Svarte 04/09/2008 kl. 21:30
kilden bruker

stemmer
137

Jeg bare legge dette for å være presis:

Alle andre svar viser til moduler . Den opprinnelige spørsmålet eksplisitt nevnt __all__i __init__.pyfiler, så dette handler om python pakker .

Vanligvis __all__kommer bare inn i bildet når from xxx import *variant av importsetningen brukes. Dette gjelder pakker så vel som for moduler.

Virkemåten for modulene er forklart i de andre svar. Den nøyaktige oppførsel for pakker er beskrevet her i detalj.

Kort sagt, __all__på pakkenivå gjør omtrent det samme som for moduler, bortsett fra at det dreier seg om moduler i pakken (i motsetning til å angi navn i modulen ). Så __all__spesifiserer alle moduler som skal lastes og importert til gjeldende navnerom når oss bruke from package import *.

Den store forskjellen er at når du utelater erklæringen __all__i en pakke er __init__.py, uttalelsen from package import *vil ikke importere noe som helst (med unntak forklart i dokumentasjonen, se link over).

På den annen side, hvis du utelater __all__i en modul, den "hovedrollen import" vil importere alle navn (ikke starter med en understrekning) definert i modulen.

Svarte 16/05/2013 kl. 19:01
kilden bruker

stemmer
108

Forklar __all__ i Python?

Jeg får se den variable __all__sett i forskjellige __init__.pyfiler.

Hva gjør denne?

Hva gjør __all__gjøre?

Det erklærer semantisk "offentlige" navn fra en modul. Hvis det er et navn i __all__, er brukere forventes å bruke det, og de kan ha en forventning om at det ikke vil endre seg.

Det vil også ha programma påvirker:

import *

__all__i en modul, for eksempel module.py:

__all__ = ['foo', 'Bar']

betyr at når du import *fra modulen, bare de navnene i __all__importeres:

from module import *               # imports foo and Bar

dokumentasjonsverktøy

Dokumentasjon og kode autofullføringsord verktøy kan (faktisk bør) også undersøke __all__for å finne ut hva navnene vise som er tilgjengelig fra en modul.

__init__.py gjør en katalog en Python pakke

Fra docs :

De __init__.pyfilene er nødvendige for å gjøre Python behandle kataloger som inneholder pakker; Dette er gjort for å hindre kataloger med et felles navn, som for eksempel streng, utilsiktet skjule gyldige moduler som oppstår senere på modulen søkebanen.

I det enkleste tilfellet, __init__.pykan bare være en tom fil, men det kan også utføre initialisering kode for pakken eller angi __all__variabel.

__init__.pykan erklære __all__for en pakke .

Administrere en API:

En pakke er vanligvis bygget opp av moduler som kan innføre hverandre, men som nødvendigvis er knyttet sammen med en __init__.pyfil. Denne filen er det som gjør katalogen en faktisk Python pakke. For eksempel si at du har følgende:

 package/
   |-__init__.py # makes directory a Python package
   |-module_1.py
   |-module_2.py

i __init__.pydu skriver:

from module_1 import *
from module_2 import *

og module_1du har:

__all__ = ['foo',]

og module_2du har:

__all__ = ['Bar',]

Og nå har presentert en komplett api at noen andre kan bruke når de importerer pakken din, som så:

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

Og de vil ikke ha alle de andre navnene du brukte når du oppretter moduler fylle opp packagenavnerommet.

__all__ i __init__.py

Etter mer arbeid, kanskje du har bestemt at modulene er for store og må deles opp. Så du gjøre følgende:

 package/
   |-__init__.py
   |-module_1/
   |  |-__init__.py
   |  |-foo_implementation.py
   |-module_2/
      |-__init__.py
      |-Bar_implementation.py

Og i hver __init__.pyerklære deg en __all__, for eksempel i module_1:

from foo_implementation import *
__all__ = ['foo']

Og module_2 er __init__.py:

from Bar_implementation import *
__all__ = ['Bar']

Og du kan enkelt legge ting til API som du kan styre på underpakke nivå i stedet for underpakke modulnivå. Hvis du vil legge til et nytt navn til API, du bare oppdatere __init__.py, for eksempel i module_2:

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

Og hvis du ikke er klar til å publisere Bazpå øverste nivå API, i øverste nivå __init__.pykan du ha:

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

og hvis brukerne er klar over tilgjengeligheten av Baz, kan de bruke det:

import package
package.Baz()

men hvis de ikke vet om det, andre verktøy (som pydoc vil) ikke informere dem.

Du kan senere endre det når Bazer klar for prime time:

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

Prefixing _versus __all__:

Som standard vil Python eksportere alle navn som ikke begynner med en _. Du absolutt kan stole på denne mekanismen. Noen pakker i Python standard bibliotek, faktisk, gjør stole på dette, men å gjøre det, de alias sin import, for eksempel i ctypes/__init__.py:

import os as _os, sys as _sys

Bruk av _konvensjonen kan være mer elegant fordi det fjerner redundans navngi navnene igjen. Men det legger redundans for import (hvis du har mange av dem), og det er lett å glemme å gjøre dette konsekvent - og det siste du ønsker er å ha til ubestemt tid støtte noe du har til hensikt å være en implementering detalj, bare fordi du glemte å prefiks en _når navngi en funksjon.

Jeg personlig skrive en __all__tidlig i min utviklingsprosessen for moduler slik at andre som kan bruke min kode vet hva de skal bruke og ikke bruke.

De fleste pakker i standard bibliotek også bruke __all__.

Når unngå __all__fornuftig

Det er fornuftig å holde seg til _prefikset konvensjonen i stedet for __all__når:

  • Du er fortsatt i tidlig utvikling modus og har ingen brukere, og er stadig tilpasning API.
  • Kanskje du har brukere, men du må unittests som dekker API, og du fortsatt aktivt legge til API og tilpasning i utvikling.

en exportdekoratør

Ulempen med å bruke __all__er at du må skrive navn på funksjoner og klasser blir eksportert to ganger - og informasjonen holdes atskilt fra definisjonene. Vi kan bruke en dekoratør å løse dette problemet.

Jeg fikk ideen for en slik eksport dekoratør fra David Beazley tale på emballasjen. Denne implementeringen ser ut til å fungere godt i CPython tradisjonelle importør. Hvis du har en spesiell import krok eller system, vet jeg ikke garantere det, men hvis du adoptere den, er det ganske trivielt å bakke ut - du trenger bare å legge til navnene manuelt tilbake i__all__

Så i, for eksempel, et verktøy bibliotek, ville du definere dekoratør:

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

og da, hvor du vil definere en __all__, gjør du dette:

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

Og dette fungerer fint om kjøres som hoved- eller importert av en annen funksjon.

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

$ python run.py
main

Og API klargjøring med import *vil fungere også:

$ 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
Svarte 29/02/2016 kl. 21:58
kilden bruker

stemmer
83

Det endrer også hva pydoc viser:

module1.py

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

module2.py

__all__ = ['a', 'b']

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

$ Pydoc module1

Hjelp modul module1:

NAVN
    module1

FIL
    module1.py

DATA 
    en = 'A'
     b = 'B'
     c = 'C'

$ Pydoc module2

Hjelp modul module2:

NAVN
    module2

FIL
    module2.py

DATA 
    __all__ = [ 'a', 'b']
     en = 'A'
     b = 'B'

Jeg erklærer __all__i alle mine moduler, samt understreking interne detaljer, disse virkelig hjelpe når du bruker ting du aldri har brukt før i levende tolk økter.

Svarte 15/05/2010 kl. 03:22
kilden bruker

stemmer
49

Fra (en uoffisiell) Python Annonse Wiki :

De offentlige navn som er definert av en modul bestemmes ved å kontrollere modulens navnerom for en variabel som heter __all__; hvis den er definert, må det være en sekvens av strenger som er navnene som er angitt eller importert av modulen. Navnene som er gitt i __all__er alle vurdert offentlige og er pålagt å eksistere. Hvis __all__ikke er definert, settet av offentlige navnene inkluderer alle navn som finnes i modulen navnerom som ikke begynner med en understrek ( "_"). __all__bør inneholde hele det offentlige API. Det er ment for å unngå uhell eksportere elementene som ikke er en del av API (for eksempel bibliotekmoduler som ble importert og brukt i modulen).

Svarte 04/09/2008 kl. 21:31
kilden bruker

stemmer
19

__all__tilpasser stjernen ifrom <module> import *

__all__tilpasser stjernen ifrom <package> import *


En modul er en .pyfil ment å bli importert.

En pakke er en katalog med en __init__.pyfil. En pakke inneholder vanligvis moduler.

""" cheese.py """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__lar mennesker kjenner den "offentlige" funksjonene i en modul . [ @AaronHall ] Også gjenkjenner pydoc dem. [ @Longpoke ]

fra modul import *

Se hvordan swissog cheddarer brakt til det lokale navne, men ikke 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

Uten __all__, et symbol (som ikke begynner med en understrekning) ville ha vært tilgjengelig.


Importen uten *påvirkes ikke av__all__


import modul

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

fra modulimport navn

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

import modul som localname

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

I __init__.pyfilen av en pakke __all__ er en liste over strenger med navnene på offentlige moduler eller andre gjenstander. Disse funksjonene er tilgjengelige for joker import. Som med moduler, __all__tilpasser den *når wildcard-import fra pakken. [ @MartinStettner ]

Her er et utdrag fra 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...

    ]

bør unngås joker import ... som de [forvirre] lesere og mange automatiserte verktøy.

[ PEP 8 , @ToolmakerSteve]

Svarte 20/03/2016 kl. 20:20
kilden bruker

stemmer
7

__all__benyttes til å dokumentere den offentlige API av en Python modul. Selv om det er valgfritt, __all__bør brukes.

Her er den relevante utdrag fra Python språk referansen :

De offentlige navn som er definert av en modul bestemmes ved å kontrollere modulens navnerom for en variabel som heter __all__; hvis den er definert, må det være en sekvens av strenger som er navnene som er angitt eller importert av modulen. Navnene som er gitt i __all__er alle vurdert offentlige og er pålagt å eksistere. Hvis __all__ikke er definert, settet av offentlige navnene inkluderer alle navn som finnes i modulen navnerom som ikke begynner med en understrek ( '_'). __all__bør inneholde hele det offentlige API. Det er ment for å unngå uhell eksportere elementene som ikke er en del av API (for eksempel bibliotekmoduler som ble importert og brukt i modulen).

PEP 8 bruker lignende ordlyd, men det gjør det også klart at importerte navnene er ikke en del av det offentlige API når __all__er fraværende:

For å bedre støtte introspeksjon, bør modulene eksplisitt deklarere navnene i sin offentlige API ved hjelp av __all__attributtet. Innstilling __all__til en tom liste indikerer at modulen har ingen offentlig API.

[...]

Importerte navnene bør alltid vurderes en implementering detalj. Andre moduler må ikke stole på indirekte tilgang til slike importerte navn med mindre de er en eksplisitt dokumentert del av inneholder modulen API, som for eksempel os.patheller en pakke sin __init__modul som eksponerer funksjonalitet fra submoduler.

Videre, som påpekt i andre svar, __all__brukes til å aktivere wildcard import for pakker :

Importen uttalelse bruker følgende inndeling: Hvis en pakke er __init__.pykoden definerer en liste med navnet __all__, er det tatt å være på listen over modulnavn som skal importeres når from package import *er oppstått.

Svarte 26/04/2016 kl. 01:39
kilden bruker

stemmer
2

korte svaret

__all__påvirker from <module> import *uttalelser.

lange svaret

Tenk på dette eksemplet:

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

i foo/__init__.py:

  • (Implisitt) Hvis vi ikke definerer __all__, så from foo import *vil bare importere navnene definert i foo/__init__.py.

  • (Explicit) Hvis vi definerer __all__ = [], så from foo import *vil importere ingenting.

  • (Explicit) Hvis vi definerer __all__ = [ <name1>, ... ], så from foo import *vil bare importere disse navnene.

Merk at i den implisitte fall vil python ikke importere navn som starter med _. Du kan imidlertid tvinge importere slike navn ved hjelp __all__.

Du kan vise Python dokumentet her .

Svarte 03/04/2018 kl. 01:19
kilden bruker

stemmer
1

I tillegg til de eksisterende svar, __all__ikke behøver å være en liste. Per dokumentasjon på importuttalelsen , hvis det er definert, __all__må være en sekvens av strenger som er navn som er definert eller importert av modulen. Så du kan like godt bruke en tuppel å spare noen minne og CPU-sykluser. Bare ikke glem et komma i tilfelle modulen definerer en enkelt offentlig navn:

__all__ = ('some_name',)

Svarte 09/01/2019 kl. 14:48
kilden bruker

stemmer
0

Dette er klart definert i PEP8 her :

Global variabelnavn

(La oss håpe at disse variablene er ment for bruk i en modul bare.) Konvensjonene er omtrent de samme som for funksjoner.

Moduler som er utviklet for bruk via from M import *bør bruke __all__mekanisme for å hindre eksport globals, eller bruke den eldre konvensjonen av prefikset slike Globals med en understrek (som du kanskje ønsker å gjøre for å indikere disse globals er "modulen ikke-offentlig").

PEP8 gir koding konvensjoner for Python koden som omfatter standardbibliotek i hoved Python fordeling. Jo mer du følger dette, er du nærmere til opprinnelsen.

Svarte 17/06/2019 kl. 20:55
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more