Eu tenho usado o Python cada vez mais e continuo vendo a variável __all__
definida em __init__.py
arquivos diferentes . Alguém pode explicar o que isso faz?
python
syntax
namespaces
varikin
fonte
fonte
__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.import *
(como por exemplotk
). Uma boa dica, se esse for o caso, é a presença__all__
ou nomes começando com sublinhado no código do módulo.tk
fosse lançado hoje (ou mesmo em 2012), a prática recomendada seria o usofrom tk import *
. Eu acho que a prática é aceita devido à inércia, não ao design intencional.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 quandofrom <module> import *
usados no módulo.Por exemplo, o código a seguir em um
foo.py
exporta explicitamente os símbolosbar
ebaz
:Esses símbolos podem ser importados da seguinte maneira:
Se o
__all__
comentário acima for comentado, esse código será executado até a conclusão, pois o comportamento padrão deimport *
é 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__
afetafrom <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 comfrom <module> import <member>
.fonte
print(baz())
?print(baz)
imprime algo como<function baz at 0x7f32bc363c10>
enquantoprint(baz())
imprimebaz
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 exemplomodule.py
:significa que, quando você
import *
do módulo, apenas os nomes no__all__
são importados: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 PythonDos documentos :
Assim, o
__init__.py
pode 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__.py
arquivo. Esse arquivo é o que torna o diretório um pacote Python real. Por exemplo, digamos que você tenha os seguintes arquivos em um pacote:Vamos criar esses arquivos com o Python para que você possa acompanhar - você pode colar o seguinte em um shell do Python 3:
E agora você apresentou uma API completa que outra pessoa pode usar quando importar seu pacote, assim:
E o pacote não terá todos os outros detalhes de implementação que você usou ao criar seus módulos sobrecarregando o
package
espaç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:
Primeiro, crie os diretórios do subpacote com os mesmos nomes dos módulos:
Mova as implementações:
crie
__init__.py
s para os subpacotes que declaram o__all__
para cada um:E agora você ainda tem a API provisionada no nível do pacote:
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:E se você não estiver pronto para publicar
Baz
na API de nível superior, em seu nível superior,__init__.py
você poderá ter:e se seus usuários estiverem cientes da disponibilidade de
Baz
, eles poderão usá-lo:mas se eles não souberem disso, outras ferramentas (como pydoc ) não os informarão.
Mais tarde, você pode alterar isso quando
Baz
estiver pronto para o horário nobre: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, emctypes/__init__.py
: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 sentidoFaz sentido seguir a
_
convenção de prefixo em vez de__all__
:Um
export
decoradorA 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:
e então, onde você definiria um
__all__
, faça o seguinte:E isso funciona bem, seja executado como principal ou importado por outra função.
E o provisionamento da API
import *
também funcionará:fonte
@export
decorador.__init__.py
eo uso de__all__
__all__
está correto.__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.module_1
emodule_2
; é OK para incluir uma explícitadel module_1
em__init__.py
? Estou errado em pensar que isso vale a pena?Estou apenas adicionando isso para ser preciso:
Todas as outras respostas se referem aos módulos . A pergunta original mencionada explicitamente
__all__
nos__init__.py
arquivos, portanto, trata-se de pacotes python .Geralmente,
__all__
só entra em jogo quando afrom xxx import *
variante daimport
declaraçã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 usamosfrom package import *
.A grande diferença é que, quando você omitir a declaração de
__all__
em um pacote__init__.py
, a instruçãofrom 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.fonte
from package import *
ainda importará tudo o que estiver definido__init__.py
, mesmo que não existaall
. A diferença importante é que, sem__all__
ele, não importará automaticamente nenhum módulo definido no diretório do pacote.Também muda o que o pydoc mostrará:
module1.py
module2.py
$ pydoc module1
$ pydoc module2
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.fonte
__all__
personaliza*
emfrom <module> import *
__all__
personaliza*
emfrom <package> import *
Um módulo é um
.py
arquivo que deve ser importado.Um pacote é um diretório com um
__init__.py
arquivo. Um pacote geralmente contém módulos.MÓDULOS
__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
swiss
echeddar
são trazidos para o espaço para nome local, mas nãogouda
: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
dos nomes de importação do módulo
módulo de importação como localname
PACOTES
No
__init__.py
arquivo 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
: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__.py
são importados:[ PEP 8 , @ToolmakerSteve]
fonte
from <package> import *
sem__all__
em__init__.py
que está não importar qualquer um dos módulos .__init__.py
fosse 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?De (An Unofficial) Python Wiki Referência :
fonte
__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 :
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:Além disso, como indicado em outras respostas,
__all__
é usado para ativar a importação de curingas para pacotes :fonte
Resposta curta
__all__
afetafrom <module> import *
declarações.Resposta longa
Considere este exemplo:
Em
foo/__init__.py
:(Implícito) Se não definirmos
__all__
,from foo import *
importará apenas os nomes definidos emfoo/__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 .
fonte
__all__
afeta comofrom 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 umafrom
instrução:As
*
solicitações para que todos os atributos do módulofoo
(exceto aqueles que começam com sublinhados) sejam vinculados como variáveis globais no módulo de importação. Quandofoo
tem um atributo__all__
, o valor do atributo é a lista dos nomes que estão vinculados por esse tipo defrom
instrução.Se
foo
é um pacote e__init__.py
define uma lista com nome__all__
, é considerada a lista de nomes de sub-módulos que devem ser importados quandofrom foo import *
encontrados. Se__all__
não estiver definido, a instruçãofrom 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 naimport
instruçã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:Veja também Por que "import *" é ruim?
fonte
Isso é definido no PEP8 aqui :
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.
fonte