Alguém pode explicar __all__ em Python?


983

Eu tenho usado o Python cada vez mais e continuo vendo a variável __all__definida em __init__.pyarquivos diferentes . Alguém pode explicar o que isso faz?

Respostas:


566

É uma lista de objetos públicos desse módulo, conforme interpretado por import *. Ele substitui o padrão de ocultar tudo o que começa com um sublinhado.


146
Objetos que começam com um sublinhado, ou não são mencionados __all__se __all__estiver presente, não são exatamente ocultos; eles podem ser vistos e acessados ​​perfeitamente normalmente, se você souber o nome deles. É apenas no caso de uma "importação *", que não é recomendada de qualquer maneira, que a distinção tenha algum peso.
Brandon Rhodes

28
@BrandonRhodes: isso também não é verdade: é recomendável importar apenas os módulos que você sabe que foram projetados import *(como por exemplo tk). Uma boa dica, se esse for o caso, é a presença __all__ou nomes começando com sublinhado no código do módulo.
Flying sheep

12
Interfaces públicas e internas - python.org/dev/peps/pep-0008/#id50 , Para oferecer melhor suporte à introspecção, os módulos devem declarar explicitamente os nomes em sua API pública usando o atributo __all__. Definir __all__ como uma lista vazia indica que o módulo não possui API pública.
debug

Não tenho certeza de que, se tkfosse lançado hoje (ou mesmo em 2012), a prática recomendada seria o uso from tk import *. Eu acho que a prática é aceita devido à inércia, não ao design intencional.
chepner

Como BrandonRhodes pontos fora isso realmente não é correta
duhaime

947

Vinculado a, mas não mencionado explicitamente aqui, é exatamente quando __all__é usado. É uma lista de cadeias que definem quais símbolos em um módulo serão exportados quando from <module> import *usados ​​no módulo.

Por exemplo, o código a seguir em um foo.pyexporta explicitamente os símbolos bare baz:

__all__ = ['bar', 'baz']

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

Esses símbolos podem ser importados da seguinte maneira:

from foo import *

print(bar)
print(baz)

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

Se o __all__comentário acima for comentado, esse código será executado até a conclusão, pois o comportamento padrão de import *é importar todos os símbolos que não começam com um sublinhado, do espaço de nome fornecido.

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

NOTA: __all__ afeta from <module> import *apenas o comportamento. Os membros que não são mencionados __all__ainda estão acessíveis de fora do módulo e podem ser importados com from <module> import <member>.


1
não devemos imprimir baz como print(baz())?
John Cole

@JohnCole baz é objeto de função e baz () executará o objeto de função
Bhanu Tez

@BhanuTez exatamente. Então print(baz)imprime algo como <function baz at 0x7f32bc363c10>enquanto print(baz())imprimebaz
John Cole

223

Explique __all__ em Python?

Eu continuo vendo a variável __all__definida em __init__.pyarquivos diferentes .

O que isso faz?

O que __all__faz?

Ele declara os nomes semanticamente "públicos" de um módulo. Se houver um nome __all__, espera-se que os usuários o usem e eles podem ter a expectativa de que isso não será alterado.

Também terá efeitos programáticos:

import *

__all__em um módulo, por exemplo module.py:

__all__ = ['foo', 'Bar']

significa que, quando você import *do módulo, apenas os nomes no __all__são importados:

from module import *               # imports foo and Bar

Ferramentas de documentação

As ferramentas de preenchimento automático de documentação e código também podem (na verdade, devem) inspecionar __all__para determinar quais nomes serão exibidos como disponíveis em um módulo.

__init__.py transforma um diretório em um pacote Python

Dos documentos :

Os __init__.pyarquivos são necessários para fazer o Python tratar os diretórios como contendo pacotes; isso é feito para impedir que diretórios com um nome comum, como string, ocultem acidentalmente módulos válidos que ocorrem posteriormente no caminho de pesquisa do módulo.

No caso mais simples, __init__.pypode ser apenas um arquivo vazio, mas também pode executar o código de inicialização do pacote ou definir a __all__variável.

Assim, o __init__.pypode declarar o __all__para um pacote .

Gerenciando uma API:

Um pacote geralmente é composto de módulos que podem importar um ao outro, mas necessariamente vinculados a um __init__.pyarquivo. Esse arquivo é o que torna o diretório um pacote Python real. Por exemplo, digamos que você tenha os seguintes arquivos em um pacote:

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

Vamos criar esses arquivos com o Python para que você possa acompanhar - você pode colar o seguinte em um shell do 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
""")

E agora você apresentou uma API completa que outra pessoa pode usar quando importar seu pacote, assim:

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

E o pacote não terá todos os outros detalhes de implementação que você usou ao criar seus módulos sobrecarregando o packageespaço para nome.

__all__ no __init__.py

Depois de mais trabalho, talvez você tenha decidido que os módulos são muito grandes (como milhares de linhas?) E precisam ser divididos. Então você faz o seguinte:

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

Primeiro, crie os diretórios do subpacote com os mesmos nomes dos módulos:

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

Mova as implementações:

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

crie __init__.pys para os subpacotes que declaram o __all__para cada um:

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

E agora você ainda tem a API provisionada no nível do pacote:

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

E você pode facilmente adicionar à sua API coisas que você pode gerenciar no nível do subpacote, em vez do nível do módulo do subpacote. Se você deseja adicionar um novo nome à API, basta atualizar o __init__.py, por exemplo, no module_2:

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

E se você não estiver pronto para publicar Bazna API de nível superior, em seu nível superior, __init__.pyvocê poderá ter:

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

e se seus usuários estiverem cientes da disponibilidade de Baz, eles poderão usá-lo:

import package
package.Baz()

mas se eles não souberem disso, outras ferramentas (como pydoc ) não os informarão.

Mais tarde, você pode alterar isso quando Bazestiver pronto para o horário nobre:

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

Prefixando _versus __all__:

Por padrão, o Python exportará todos os nomes que não começam com um _. Você certamente poderia confiar nesse mecanismo. Alguns pacotes na biblioteca padrão do Python, de fato, não contar com isso, mas a fazê-lo, eles apelido suas importações, por exemplo, em ctypes/__init__.py:

import os as _os, sys as _sys

O uso da _convenção pode ser mais elegante, pois remove a redundância de nomear os nomes novamente. Mas adiciona a redundância para importações (se houver muitas) e é fácil esquecer de fazer isso de forma consistente - e a última coisa que você quer é ter que suportar indefinidamente algo que você pretendia ser apenas um detalhe de implementação, apenas porque você esqueceu de prefixar um _ao nomear uma função.

Eu pessoalmente escrevi um __all__ciclo de vida de desenvolvimento no início de módulos para que outras pessoas que possam usar meu código saibam o que devem usar e não usar.

A maioria dos pacotes na biblioteca padrão também usa __all__.

Evitar __all__faz sentido

Faz sentido seguir a _convenção de prefixo em vez de __all__:

  • Você ainda está no modo de desenvolvimento inicial, não possui usuários e está constantemente aprimorando sua API.
  • Talvez você tenha usuários, mas possui unittests que cobrem a API e ainda está adicionando ativamente à API e aprimorando o desenvolvimento.

Um exportdecorador

A desvantagem de usar __all__é que você precisa escrever os nomes das funções e classes que estão sendo exportadas duas vezes - e as informações são mantidas separadas das definições. Nós poderia usar um decorador para resolver este problema.

Tive a ideia de um decorador de exportação desse discurso de David Beazley sobre embalagem. Essa implementação parece funcionar bem no importador tradicional do CPython. Se você tiver um sistema ou gancho de importação especial, eu não garanto, mas se você adotá-lo, é bastante trivial voltar atrás - você só precisará adicionar manualmente os nomes novamente ao diretório__all__

Portanto, em uma biblioteca de utilidades, por exemplo, você definiria o decorador:

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

e então, onde você definiria um __all__, faça o seguinte:

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

E isso funciona bem, seja executado como principal ou importado por outra função.

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

$ python run.py
main

E o provisionamento da API import *também funcionará:

$ 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

1
Referência cruzada: mencionei seu decorador nesta resposta da CW à pergunta de como escrever um @exportdecorador.
MvG 27/01

13
Isto tem handedly sido a única resposta mais útil que tenho visto em relação ao ajudar um relativamente novo desenvolvedor python entender o processo de importação de módulos / pacotes com __init__.pyeo uso de__all__
Brett Reinhard

Isto me ajuda muito. Meu problema, portanto, é que os submódulos que eu quero importar são todos arquivos gerados com muito cruft em seus símbolos que eu gostaria de remover, sem ter que garantir manualmente que __all__está correto.
Mike C

@ MikeC, então talvez você deva gerar o seu __all__também - mas eu diria que você tem uma API instável ... Isso seria algo para se ter alguns testes de aceitação abrangentes.
Aaron Hall

@AaronHall "eles não terão todos os outros nomes ... bagunçando o espaço para nome do pacote" Mas eles terão os nomes module_1e module_2; é OK para incluir uma explícita del module_1em __init__.py? Estou errado em pensar que isso vale a pena?
Mike C

176

Estou apenas adicionando isso para ser preciso:

Todas as outras respostas se referem aos módulos . A pergunta original mencionada explicitamente __all__nos __init__.pyarquivos, portanto, trata-se de pacotes python .

Geralmente, __all__só entra em jogo quando a from xxx import *variante da importdeclaração é usada. Isso se aplica aos pacotes e aos módulos.

O comportamento dos módulos é explicado nas outras respostas. O comportamento exato dos pacotes é descrito aqui em detalhes.

Em resumo, __all__no nível do pacote faz aproximadamente a mesma coisa que para os módulos, exceto que trata dos módulos dentro do pacote (em contraste com a especificação de nomes dentro do módulo ). Assim, __all__especifica todos os módulos que devem ser carregados e importados para o espaço para nome atual quando usamos from package import *.

A grande diferença é que, quando você omitir a declaração de __all__em um pacote __init__.py, a instrução from package import *não importará nada (com exceções explicadas na documentação, consulte o link acima).

Por outro lado, se você omitir __all__um módulo, a "importação com estrela" importará todos os nomes (não começando com um sublinhado) definidos no módulo.


29
from package import *ainda importará tudo o que estiver definido __init__.py, mesmo que não exista all. A diferença importante é que, sem __all__ele, não importará automaticamente nenhum módulo definido no diretório do pacote.
Nikratio

Quando all contém [foo, bar] e no arquivo test.py, se usarmos: from package import *, foo e bar são importados no espaço de nomes local de test.py ou no próprio espaço de nomes foo and bars?
variável

87

Também muda o que o pydoc mostrará:

module1.py

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

module2.py

__all__ = ['a', 'b']

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

$ pydoc module1

Ajuda no módulo module1:

NOME
    Módulo 1

ARQUIVO
    module1.py

DADOS 
    a = 'A'
     b = 'B'
     c = 'C'

$ pydoc module2

Ajuda no módulo module2:

NOME
    module2

ARQUIVO
    module2.py

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

Declaro __all__em todos os meus módulos, além de sublinhar os detalhes internos, que realmente ajudam ao usar coisas que você nunca usou antes em sessões de intérpretes ao vivo.


54

__all__personaliza *emfrom <module> import *

__all__personaliza *emfrom <package> import *


Um módulo é um .pyarquivo que deve ser importado.

Um pacote é um diretório com um __init__.pyarquivo. Um pacote geralmente contém módulos.


MÓDULOS

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

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__permite que os humanos conheçam os recursos "públicos" de um módulo . [ @AaronHall ] Além disso, o pydoc os reconhece. [ @Longpoke ]

da importação do módulo *

Veja como swisse cheddarsão trazidos para o espaço para nome local, mas não 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

Sem __all__, qualquer símbolo (que não comece com um sublinhado) estaria disponível.


As importações sem *não são afetadas por__all__


módulo de importação

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

dos nomes de importação do módulo

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

módulo de importação como localname

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

PACOTES

No __init__.pyarquivo de um pacote, __all__ há uma lista de cadeias com os nomes de módulos públicos ou outros objetos. Esses recursos estão disponíveis para importações de caracteres curinga. Como nos módulos, __all__personaliza a *importação de curingas do pacote. [ @MartinStettner ]

Aqui está um trecho do 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...

    ]

O caso padrão, asterisco sem no __all__para um pacote , é complicado, porque o comportamento óbvio seria caro: usar o sistema de arquivos para procurar todos os módulos no pacote. Em vez disso, na minha leitura dos documentos, apenas os objetos definidos em __init__.pysão importados:

Se __all__não for definido, a declaração from sound.effects import *não não importar todos os submódulos do pacote sound.effectspara o namespace atual; ele garante apenas que o pacote sound.effectsfoi importado (possivelmente executando qualquer código de inicialização __init__.py) e depois importa os nomes definidos no pacote. Isso inclui qualquer nome definido (e sub-módulos explicitamente carregados) por __init__.py. Ele também inclui quaisquer submódulos do pacote que foram explicitamente carregados por instruções de importação anteriores.


As importações de caracteres curinga ... devem ser evitadas, pois confundem os leitores e muitas ferramentas automatizadas.

[ PEP 8 , @ToolmakerSteve]


2
Eu realmente gosto desta resposta, mas eu estou perdendo as informações sobre o que é o comportamento padrão para from <package> import *sem __all__em __init__.pyque está não importar qualquer um dos módulos .
Radzak

Obrigado @Jatimir, esclareci o melhor que pude sem realizar experimentos. Eu quase quis dizer que este caso (asterisco sem todos para um pacote) se comporta da mesma forma que se __init__.pyfosse um módulo . Mas não tenho certeza se isso é exato ou, em particular, se objetos com prefixo sublinhado são excluídos. Além disso, separei mais claramente as seções sobre MÓDULOS e PACOTES. Seus pensamentos?
21419 Bob Stein

49

De (An Unofficial) Python Wiki Referência :

Os nomes públicos definidos por um módulo são determinados verificando o espaço de nomes do módulo para uma variável denominada __all__; se definido, deve ser uma sequência de cadeias que são nomes definidos ou importados por esse módulo. Os nomes dados __all__são todos considerados públicos e devem existir. Se __all__não estiver definido, o conjunto de nomes públicos inclui todos os nomes encontrados no espaço para nome do módulo que não começam com um caractere sublinhado ("_"). __all__deve conter toda a API pública. Destina-se a evitar a exportação acidental de itens que não fazem parte da API (como módulos de biblioteca que foram importados e usados ​​dentro do módulo).


O link listado está morto. mas o texto encontrado verbatim em vdocuments.net/... & aqui: dokumen.tips/documents/reference-567bab8d6118a.html
JayRizzo

8

__all__é usado para documentar a API pública de um módulo Python. Embora seja opcional, __all__deve ser usado.

Aqui está o trecho relevante da referência da linguagem Python :

Os nomes públicos definidos por um módulo são determinados verificando o espaço de nomes do módulo para uma variável denominada __all__; se definido, deve ser uma sequência de cadeias que são nomes definidos ou importados por esse módulo. Os nomes dados __all__são todos considerados públicos e devem existir. Se __all__não estiver definido, o conjunto de nomes públicos inclui todos os nomes encontrados no espaço para nome do módulo que não começam com um caractere sublinhado ('_'). __all__deve conter toda a API pública. Destina-se a evitar a exportação acidental de itens que não fazem parte da API (como módulos de biblioteca que foram importados e usados ​​dentro do módulo).

O PEP 8 usa palavras semelhantes, embora também deixe claro que nomes importados não fazem parte da API pública quando __all__estão ausentes:

Para oferecer melhor suporte à introspecção, os módulos devem declarar explicitamente os nomes em sua API pública usando o __all__atributo A configuração __all__para uma lista vazia indica que o módulo não possui API pública.

[...]

Os nomes importados devem sempre ser considerados um detalhe de implementação. Outros módulos não devem confiar no acesso indireto a esses nomes importados, a menos que sejam uma parte explicitamente documentada da API do módulo que contém, como os.pathum __init__módulo de um pacote que exponha a funcionalidade dos submódulos.

Além disso, como indicado em outras respostas, __all__é usado para ativar a importação de curingas para pacotes :

A instrução de importação usa a seguinte convenção: se o __init__.pycódigo de um pacote definir uma lista denominada __all__, será considerada a lista de nomes de módulos que devem ser importados quando from package import *encontrados.


8

Resposta curta

__all__afeta from <module> import *declarações.

Resposta longa

Considere este exemplo:

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

Em foo/__init__.py:

  • (Implícito) Se não definirmos __all__, from foo import *importará apenas os nomes definidos em foo/__init__.py.

  • (Explícito) Se definirmos __all__ = [], from foo import *não importará nada.

  • (Explícito) Se definirmos __all__ = [ <name1>, ... ], from foo import *importará apenas esses nomes.

Observe que, no caso implícito, o python não importará nomes começando com _. No entanto, você pode forçar a importação desses nomes usando __all__.

Você pode visualizar o documento Python aqui .


5

__all__afeta como from foo import *funciona.

O código que está dentro do corpo de um módulo (mas não no corpo de uma função ou classe) pode usar um asterisco ( *) em uma frominstrução:

from foo import *

As *solicitações para que todos os atributos do módulo foo(exceto aqueles que começam com sublinhados) sejam vinculados como variáveis ​​globais no módulo de importação. Quando footem um atributo __all__, o valor do atributo é a lista dos nomes que estão vinculados por esse tipo de frominstrução.

Se fooé um pacote e __init__.pydefine uma lista com nome __all__, é considerada a lista de nomes de sub-módulos que devem ser importados quando from foo import *encontrados. Se __all__não estiver definido, a instrução from foo import *importará quaisquer nomes definidos no pacote. Isso inclui qualquer nome definido (e sub-módulos explicitamente carregados) por __init__.py.

Observe que __all__não precisa ser uma lista. Conforme a documentação na importinstrução , se definida, __all__deve haver uma sequência de seqüências de caracteres que são nomes definidos ou importados pelo módulo. Portanto, você também pode usar uma tupla para economizar alguns ciclos de memória e CPU. Apenas não esqueça uma vírgula, caso o módulo defina um único nome público:

__all__ = ('some_name',)

Veja também Por que "import *" é ruim?


1

Isso é definido no PEP8 aqui :

Nomes de variáveis ​​globais

(Vamos torcer para que essas variáveis ​​sejam usadas apenas dentro de um módulo.) As convenções são praticamente as mesmas das funções.

Os módulos projetados para uso via from M import *devem usar o __all__mecanismo para impedir a exportação de globais, ou usar a convenção anterior de prefixar esses globais com um sublinhado (o que você pode querer fazer para indicar que esses globais são "módulos não públicos").

O PEP8 fornece convenções de codificação para o código Python, que compreende a biblioteca padrão na distribuição principal do Python. Quanto mais você segue isso, mais perto está da intenção original.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.