Alguém pode explicar __all__ em Python?

votos
608

Tenho vindo a utilizar Python mais e mais, e eu continuo vendo a variável de __all__set em diferentes __init__.pyarquivos. Alguém pode explicar o que isso faz?

Publicado 04/09/2008 em 22:28
fonte usuário
Em outras línguas...                            


10 respostas

votos
659

Ligada a, mas não explicitamente mencionado aqui, é exatamente quando __all__é usado. É uma lista de strings que definem o que símbolos em um módulo será exportado quando from <module> import *é utilizada no módulo.

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

__all__ = ['bar', 'baz']

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

Estes símbolos podem ser importados como assim:

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__acima é comentado, este código irá então executar até a conclusão, como o comportamento padrão import *é para importar todos os símbolos que não começam com um sublinhado, a partir do namespace dado.

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

NOTA: __all__ afeta o from <module> import *único comportamento. Membros que não são mencionados no __all__ainda são acessíveis a partir de fora do módulo e podem ser importados com from <module> import <member>.

Respondeu 15/09/2008 em 16:49
fonte usuário

votos
305

É uma lista de objetos públicas desse módulo, tal como interpretado pelo import *. Ele substitui o padrão de esconder tudo o que começa com um sublinhado.

Respondeu 04/09/2008 em 22:30
fonte usuário

votos
130

Eu só estou adicionando este para ser mais preciso:

Todas as outras respostas referem-se a módulos . A pergunta original explicitamente mencionado __all__em __init__.pyarquivos, de modo que este é sobre Python pacotes .

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

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

Em suma, __all__em nível de pacote faz aproximadamente a mesma coisa que para os módulos, exceto que ele lida com módulos dentro do pacote (em contraste com a especificação de nomes dentro do módulo ). Então __all__especifica todos os módulos que serão carregados e importados para o namespace atual quando nos usar from package import *.

A grande diferença é que, quando você omitir a declaração de __all__um pacote de __init__.py, a declaração from package import *não vai importar nada (com exceções explicado na documentação, ver link acima).

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

Respondeu 16/05/2013 em 20:01
fonte usuário

votos
97

Explique __all__ em Python?

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

O que isso faz?

O que __all__fazer?

Declara os semanticamente nomes "públicas" de um módulo. Se houver um nome em __all__, os usuários são esperados para usá-lo, e eles podem ter a expectativa de que isso não vai mudar.

Ele também terá programática afeta:

import *

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

__all__ = ['foo', 'Bar']

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

from module import *               # imports foo and Bar

ferramentas de documentação

Documentação e completação automática de código ferramentas podem (na verdade, deve) também inspecionar o __all__de determinar quais nomes para mostrar como disponíveis a partir de um módulo.

__init__.py faz um diretório de um pacote Python

A partir dos documentos :

Os __init__.pyarquivos são necessários para que Python trate os diretórios como contendo pacotes; isso é feito para evitar diretórios com um nome comum, tais como cordas, de inadvertidamente esconder módulos válidos que ocorram a posteriori no caminho de pesquisa de módulo.

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

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

Gerir uma API:

Um pacote é tipicamente composta por módulos que podem importar um do outro, mas que são necessariamente amarrado junto com um __init__.pyarquivo. Esse arquivo é o que faz o diretório de um pacote Python real. Por exemplo, digamos que você tenha o seguinte:

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

no __init__.pyque você escreve:

from module_1 import *
from module_2 import *

e em module_1que você tem:

__all__ = ['foo',]

e em module_2que você tem:

__all__ = ['Bar',]

E agora você tem apresentado uma API completa que alguém pode usar quando importar o pacote, assim:

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

E eles não terão todos os outros nomes que você usou ao criar seus módulos atravancando o packagenamespace.

__all__ dentro __init__.py

Depois de mais trabalho, talvez você decidiu que os módulos são muito grande e precisa ser dividido. Então você faça o seguinte:

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

E em cada __init__.pyvocê declarar um __all__, por exemplo, em module_1:

from foo_implementation import *
__all__ = ['foo']

E module_2 de __init__.py:

from Bar_implementation import *
__all__ = ['Bar']

E você pode facilmente adicionar coisas para o seu API que você pode gerenciar no nível subpackage em vez de nível de módulo do subpackage. Se você quiser adicionar um novo nome para a API, você simplesmente atualizar o __init__.py, por exemplo, em module_2:

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

E se você não estiver pronto para publicar Bazno topo nível API, em seu nível mais alto __init__.pyvocê poderia 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 os usuários estão cientes da disponibilidade de Baz, eles podem usá-lo:

import package
package.Baz()

mas se eles não sabem sobre isso, outras ferramentas (como pydoc ) não irá informá-los.

Posteriormente, você pode mudar isso quando Bazestá pronto para o horário nobre:

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

Prefixar _contra __all__:

Por padrão, Python irá exportar todos os nomes que não começam com um _. Você certamente poderia contar com este mecanismo. Alguns pacotes na biblioteca padrão do Python, na verdade, não contam com isso, mas para fazê-lo, eles apelidar as suas importações, por exemplo, em ctypes/__init__.py:

import os as _os, sys as _sys

Usando a _convenção pode ser mais elegante porque remove a redundância de nomear os nomes novamente. Mas acrescenta a redundância para as importações (se você tem um monte deles) e é fácil se esquecer de fazer isso de forma consistente - ea última coisa que você quer é ter que suportar indefinidamente algo que você pretende ser apenas um detalhe de implementação, apenas porque você se esqueceu de prefixo um _ao nomear uma função.

Eu, pessoalmente, escrever um __all__no início da minha ciclo de desenvolvimento para os módulos para que outras pessoas que poderiam usar o meu código de saber o que eles devem usar e não usar.

A maioria dos pacotes da biblioteca padrão também usam __all__.

Quando evitando __all__faz sentido

Faz sentido manter o _convenção de prefixo em vez de __all__quando:

  • Você ainda está no modo de desenvolvimento cedo e não têm usuários, e estão constantemente a ajustar a sua API.
  • Talvez você tem usuários, mas você tem UnitTests que cobrem a API, e você ainda está adicionando activamente para a API e ajustes em desenvolvimento.

um exportdecorador

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

Eu tive a idéia para tal um decorador de exportação a partir do discurso de David Beazley na embalagem. Esta implementação parece funcionar bem em importador tradicional de CPython. Se você tem um gancho de importação especial ou sistema, eu não garanto, mas se você adotá-lo, é bastante trivial para trás para fora - você só precisa adicionar manualmente os nomes de volta para o__all__

Assim, por exemplo, uma biblioteca de utilitário, 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, em seguida, onde você definiria um __all__, você faz isso:

$ 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 se executar como principal ou importado por outra função.

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

$ python run.py
main

E provisionamento API com import *irá funcionar também:

$ 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
Respondeu 29/02/2016 em 21:58
fonte usuário

votos
83

Ele também altera o pydoc irá mostrar:

module1.py

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

module2.py

__all__ = ['a', 'b']

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

$ Module1 pydoc

Ajuda on Module Module1:

NOME
    Módulo 1

ARQUIVO
    module1.py

DADOS 
    um = 'A'
     b = 'B'
     C = 'C'

$ Module2 pydoc

Ajuda sobre módulo module2:

NOME
    module2

ARQUIVO
    module2.py

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

Declaro __all__em todos os meus módulos, bem como sublinhado detalhes internos, estes realmente ajudar ao usar coisas que você nunca usou antes em sessões de intérprete ao vivo.

Respondeu 15/05/2010 em 04:22
fonte usuário

votos
48

De (An Unofficial) Python Wiki Referência :

Os nomes públicos definidos por um módulo são determinados pela verificação namespace do módulo para uma variável chamada __all__; se definido, ele deve ser uma seqüência de cordas que são nomes definidos ou importados por esse módulo. Os nomes dados em __all__todos são considerados público e são obrigados a existir. Se __all__não estiver definido, o conjunto de nomes públicos inclui todos os nomes encontrados no namespace do módulo que não começam com um caractere sublinhado ( "_"). __all__deve conter toda a API pública. Pretende-se evitar itens acidentalmente exportadores que não fazem parte da API (tais como módulos de biblioteca que foram importadas e usadas dentro do módulo).

Respondeu 04/09/2008 em 22:31
fonte usuário

votos
17

__all__personaliza o asterisco nasfrom <module> import *

__all__personaliza o asterisco nasfrom <package> import *


Um módulo é um .pyarquivo destinado a ser importado.

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

""" cheese.py """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__permite que os seres humanos conhecer as características "públicas" de um módulo . [ @AaronHall ] Além disso, pydoc reconhece-los. [ @Longpoke ]

a partir do módulo de importação *

Veja como swisse cheddarsão trazidos para o namespace 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 começar com um sublinhado) teria sido disponíveis.


Importações sem *não são afetados por__all__


importação módulo

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

a partir do módulo de importação nomes

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

importação módulo como localname

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

No __init__.pyarquivo de um pacote __all__ é uma lista de strings com os nomes dos módulos públicos ou outros objetos. Esses recursos estão disponíveis para as importações curinga. Tal como acontece com os módulos, __all__personaliza o *quando universal-importar a partir do pacote. [ @MartinStettner ]

Aqui está um trecho do conector Python MySQL __init__.py :

__all__ = [
    'MySQLConnection', 'Connect', 'custom_error_exception',

    # Some useful constants
    'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption',
    'HAVE_CEXT',

    # Error handling
    'Error', 'Warning',

    ...etc...

    ]

importações curinga ... devem ser evitados, pois [confundir] leitores e muitas ferramentas automatizadas.

[ PEP 8 , @ToolmakerSteve]

Respondeu 20/03/2016 em 20:20
fonte usuário

votos
7

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

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

Os nomes públicos definidos por um módulo são determinados pela verificação namespace do módulo para uma variável chamada __all__; se definido, ele deve ser uma seqüência de cordas que são nomes definidos ou importados por esse módulo. Os nomes dados em __all__todos são considerados público e são obrigados a existir. Se __all__não estiver definido, o conjunto de nomes públicos inclui todos os nomes encontrados no namespace do módulo que não começam com um caractere sublinhado ( '_'). __all__deve conter toda a API pública. Pretende-se evitar itens acidentalmente exportadores que não fazem parte da API (tais como módulos de biblioteca que foram importadas e usadas dentro do módulo).

PEP 8 usa palavras similares, embora também deixa claro que nomes importados não são parte da API pública quando __all__está ausente:

Para melhor introspecção apoio, módulos deve declarar explicitamente os nomes em sua API pública usando o __all__atributo. Definindo __all__a uma lista vazia indica que o módulo não tem nenhuma API pública.

[...]

Nomes importados deve ser sempre considerada um detalhe de implementação. Outros módulos não deve contar com acesso indirecto aos nomes importados, a menos que eles são uma parte explicitamente documentadas da API do módulo que contém, como os.pathou de um pacote de __init__módulo que expõe a funcionalidade do sub-módulos.

Além disso, como apontado em outras respostas, __all__é usado para permitir curinga importação de pacotes :

A declaração de importação utiliza a seguinte convenção: se um pacote de __init__.pycódigo define uma lista com o nome __all__, é considerado como sendo a lista de nomes de módulos que devem ser importados quando from package import *é encontrado.

Respondeu 26/04/2016 em 01:39
fonte usuário

votos
1

Além das respostas existentes, __all__não tem que ser uma lista. De acordo com a documentação sobre a importdeclaração , se definido, __all__deve ser uma seqüência de cordas que são nomes definidos ou importados pelo módulo. Então, assim como você pode usar uma tupla para salvar alguns ciclos de memória e CPU. Só não se esqueça uma vírgula no caso do módulo define um único nome público:

__all__ = ('some_name',)

Respondeu 09/01/2019 em 14:48
fonte usuário

votos
1

Resposta curta

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

Resposta longa

Veja este exemplo:

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

em foo/__init__.py:

  • (Implícita) Se não definir __all__, em seguida, from foo import *irá apenas nomes de importação definido no foo/__init__.py.

  • (Explicit) Se definirmos __all__ = [], em seguida, from foo import *vai importar nada.

  • (Explicit) Se definirmos __all__ = [ <name1>, ... ], então from foo import *só vai importar esses nomes.

Note-se que no caso implícita, python não vai importar nomes começando com _. No entanto, você pode forçar a importação de tais nomes usando __all__.

Você pode visualizar o documento Python aqui .

Respondeu 03/04/2018 em 01:19
fonte usuário

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