Pregunta ¿Alguien puede explicar __all__ en Python?


He estado usando Python cada vez más, y sigo viendo la variable __all__ establecer en diferentes __init__.py archivos. ¿Alguien puede explicar lo que hace?


630
2017-09-04 21:28


origen


Respuestas:


Es una lista de objetos públicos de ese módulo, según la interpretación de import *. Anula el valor predeterminado de ocultar todo lo que comienza con un guión bajo.


318
2017-09-04 21:30



Vinculado a, pero no mencionado explícitamente aquí, es exactamente cuando __all__ es usado. Es una lista de cadenas que definen qué símbolos de un módulo se exportarán cuando from <module> import * se usa en el módulo.

Por ejemplo, el siguiente código en una foo.py explícitamente exporta los símbolos bar y baz:

__all__ = ['bar', 'baz']

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

Estos símbolos se pueden importar así:

from foo import *

print bar
print baz

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

Si el __all__ arriba está comentado, este código se ejecutará hasta su finalización, ya que el comportamiento predeterminado de import * es importar todos los símbolos que no comienzan con un guión bajo, desde el espacio de nombres dado.

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

NOTA:  __all__ afecta el from <module> import * comportamiento solo Miembros que no están mencionados en __all__ todavía se puede acceder desde fuera del módulo y se puede importar con from <module> import <member>.


676
2017-09-15 15:49



Solo estoy agregando esto para ser preciso:

Todas las otras respuestas se refieren a módulos. La pregunta original explícitamente mencionada __all__ en __init__.py archivos, así que esto es sobre python paquetes.

En general, __all__ solo entra en juego cuando from xxx import * variante de import declaración se utiliza. Esto se aplica tanto a paquetes como a módulos.

El comportamiento de los módulos se explica en las otras respuestas. Se describe el comportamiento exacto de los paquetes aquí en detalle.

En breve, __all__ en el nivel del paquete hace aproximadamente lo mismo que para los módulos, excepto que se trata de módulos dentro del paquete  (a diferencia de especificar nombres dentro del módulo) Asi que __all__ especifica todos los módulos que deben cargarse e importarse en el espacio de nombres actual cuando usamos from package import *.

La gran diferencia es que cuando omitir la declaración de __all__ en un paquete __init__.py, la declaración from package import * no importará nada en absoluto (con las excepciones explicadas en la documentación, ver enlace arriba).

Por otro lado, si omites __all__ en un módulo, la "importación con estrella" importará todos los nombres (que no comiencen con un guión bajo) definidos en el módulo.


134
2018-05-16 19:01



¿Explicar __all__ en Python?

Sigo viendo la variable __all__ establecer en diferentes __init__.py archivos.

¿Qué hace esto?

Que hace __all__ ¿hacer?

Declara los nombres semánticamente "públicos" de un módulo. Si hay un nombre en __all__, se espera que los usuarios lo usen, y pueden esperar que no cambie.

También tendrá efectos programáticos:

import *

__all__ en un módulo, p. module.py:

__all__ = ['foo', 'Bar']

significa que cuando import * del módulo, solo esos nombres en el __all__son importados:

from module import *               # imports foo and Bar

Herramientas de documentación

Las herramientas de autocompletado de documentación y código pueden (de hecho, deberían) también inspeccionar el __all__ para determinar qué nombres mostrar como disponibles desde un módulo.

__init__.py hace que un directorio sea un paquete de Python

Desde el documentos:

los __init__.py se requieren archivos para hacer que Python considere que los directorios contienen paquetes; esto se hace para evitar que los directorios con un nombre común, como una cadena, oculten involuntariamente los módulos válidos que ocurren más adelante en la ruta de búsqueda del módulo.

En el caso más simple, __init__.py puede ser solo un archivo vacío, pero también puede ejecutar el código de inicialización para el paquete o configurar el __all__ variable.

Entonces el __init__.py puede declarar el __all__ para paquete.

Administrar una API:

Un paquete se compone típicamente de módulos que pueden importarse entre sí, pero que necesariamente están vinculados con un __init__.py archivo. Ese archivo es lo que hace que el directorio sea un paquete real de Python. Por ejemplo, supongamos que tiene lo siguiente:

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

en el __init__.py usted escribe:

from module_1 import *
from module_2 import *

y en module_1 tienes:

__all__ = ['foo',]

y en module_2 tienes:

__all__ = ['Bar',]

Y ahora ha presentado una API completa que alguien más puede usar cuando importa su paquete, así:

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

Y no tendrán todos los otros nombres que usaste al crear tus módulos abarrotando el package espacio de nombres

__all__ en __init__.py

Después de más trabajo, tal vez haya decidido que los módulos son demasiado grandes y deben dividirse. Entonces haces lo siguiente:

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

Y en cada __init__.py usted declara un __all__, p.ej. en module_1:

from foo_implementation import *
__all__ = ['foo']

Y module_2's __init__.py:

from Bar_implementation import *
__all__ = ['Bar']

Y puede agregar fácilmente cosas a su API que puede administrar en el nivel de subpaquete en lugar del nivel de módulo del subpaquete. Si desea agregar un nuevo nombre a la API, simplemente actualice la __init__.py, p.ej. en module_2:

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

Y si no estás listo para publicar Baz en la API de nivel superior, en tu nivel superior __init__.py podrías tener:

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

y si sus usuarios conocen la disponibilidad de Baz, pueden usarlo:

import package
package.Baz()

pero si no lo saben, otras herramientas (como pydoc) no les informará.

Luego puedes cambiar eso cuando Baz está listo para el horario de máxima audiencia:

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

Prefijo _ versus __all__:

Por defecto, Python exportará todos los nombres que no comiencen con un _. Ciertamente podría confía en este mecanismo. Algunos paquetes en la biblioteca estándar de Python, de hecho, hacer confiar en esto, pero para hacerlo, alias sus importaciones, por ejemplo, en ctypes/__init__.py:

import os as _os, sys as _sys

Utilizando el _ la convención puede ser más elegante porque elimina la redundancia de nombrar los nombres nuevamente. Pero agrega la redundancia para las importaciones (si tiene muchas) y es fácil olvidarse de hacer esto constantemente, y lo último que desea es tener que respaldar indefinidamente algo que pretendía ser solo un detalle de implementación, simplemente porque olvidó prefijar un _ al nombrar una función.

Yo personalmente escribo un __all__Al principio de mi ciclo de vida de desarrollo para los módulos, para que otros que puedan usar mi código sepan qué deben usar y cuáles no.

La mayoría de los paquetes en la biblioteca estándar también usan __all__.

Al evitar __all__ tiene sentido

Tiene sentido apegarse a la _ prefijo convención en lugar de __all__ cuando:

  • Todavía estás en el modo de desarrollo inicial y no tienes usuarios, y constantemente modifica tu API.
  • Quizás tenga usuarios, pero tiene pruebas de unidad que cubren la API, y todavía está agregando activamente a la API y modificando en desarrollo.

Un export decorador

La desventaja de usar __all__ es que debe escribir los nombres de las funciones y clases que se exportan dos veces, y la información se mantiene separada de las definiciones. Nosotros podría usa un decorador para resolver este problema

Me llegó la idea de un decorador de exportación de la charla de David Beazley sobre el embalaje. Esta implementación parece funcionar bien en el importador tradicional de CPython. Si tiene un gancho o sistema de importación especial, no lo garantizo, pero si lo adopta, es bastante trivial retroceder; solo tendrá que volver a agregar los nombres manualmente en el __all__

Entonces, por ejemplo, en una biblioteca de utilidad, definiría el 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

y luego, donde definirías un __all__, tu hiciste esto:

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

Y esto funciona bien ya sea ejecutado como main o importado por otra función.

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

$ python run.py
main

Y aprovisionamiento API con import * funcionará también:

$ 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

105
2018-02-29 21:58



También cambia lo que pydoc mostrará:

module1.py

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

module2.py

__all__ = ['a', 'b']

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

$ pydoc module1

Ayuda en el módulo module1:

NOMBRE
    módulo 1

ARCHIVO
    module1.py

DATOS
     un = 'A'
     segundo = 'B'
     do = 'C'

$ pydoc module2

Ayuda en el módulo module2:

NOMBRE
    módulo2

ARCHIVO
    module2.py

DATOS
     __todas__ = ['a', 'b']
     un = 'A'
     segundo = 'B'

declaro __all__ en todos mis módulos, así como en subrayar detalles internos, estos realmente ayudan cuando se usan cosas que nunca antes se han usado en sesiones de intérpretes en vivo.


83
2018-05-15 03:22



De Wiki de referencia de Python (no oficial):

Los nombres públicos definidos por un módulo se determinan al verificar el espacio de nombres del módulo para una variable llamada __all__; si se define, debe ser una secuencia de cadenas que son nombres definidos o importados por ese módulo. Los nombres dados en __all__ Todos son considerados públicos y se requiere que existan. Si __all__ no está definido, el conjunto de nombres públicos incluye todos los nombres encontrados en el espacio de nombres del módulo que no comienzan con un carácter de subrayado ("_"). __all__ debe contener toda la API pública. Está destinado a evitar la exportación accidental de elementos que no forman parte de la API (como los módulos de la biblioteca que se importaron y usaron en el módulo).


48
2017-09-04 21:31



__all__ personaliza el asterisco en from <module> import *

__all__ personaliza el asterisco en from <package> import *


UN módulo es un .py archivo destinado a ser importado.

UN paquetees un directorio con un __init__.py archivo. Un paquete generalmente contiene módulos.

""" cheese.py """

__all__ = ['swiss', 'cheddar']

swiss = 4.99
cheddar = 3.99
gouda = 10.99

__all__ permite a los humanos conocer las características "públicas" de un módulo.[@ Aaron Hall]  Además, pydoc los reconoce.[@Longpoke]

de módulo importar *

Ver cómo swiss y cheddar se traen al espacio de nombres local, pero no 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

Sin __all__, cualquier símbolo (que no comience con un guión bajo) hubiera estado disponible.


Importaciones sin * no son afectados por __all__


importar módulo

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

de módulo importar nombres

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

importar módulo como nombre local

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

En el __init__.py archivo de un paquete  __all__ es una lista de cadenas con los nombres de módulos públicos u otros objetos. Esas características están disponibles para las importaciones de comodines. Al igual que con los módulos, __all__ personaliza el * cuando se importa un comodín desde el paquete.[@MartinStettner] 

Aquí hay un extracto de la 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...

    ]

Las importaciones de comodines ... deberían evitarse ya que [confunden] a los lectores y a muchas herramientas automatizadas.

[PEP 8, @ToolmakerSteve]


19
2018-03-20 20:20



__all__ se usa para documentar la API pública de un módulo de Python. Aunque es opcional, __all__ debería ser usado.

Aquí está el extracto relevante de la referencia de lenguaje Python:

Los nombres públicos definidos por un módulo se determinan al verificar el espacio de nombres del módulo para una variable llamada __all__; si se define, debe ser una secuencia de cadenas que son nombres definidos o importados por ese módulo. Los nombres dados en __all__ Todos son considerados públicos y se requiere que existan. Si __all__ no está definido, el conjunto de nombres públicos incluye todos los nombres encontrados en el espacio de nombres del módulo que no comienzan con un carácter de subrayado ('_'). __all__ debe contener toda la API pública. Está destinado a evitar la exportación accidental de elementos que no forman parte de la API (como los módulos de la biblioteca que se importaron y usaron en el módulo).

PEP 8 utiliza una redacción similar, aunque también deja en claro que los nombres importados no son parte de la API pública cuando __all__ está ausente:

Para admitir mejor la introspección, los módulos deben declarar explícitamente los nombres en su API pública utilizando el __all__ atributo. Ajuste __all__ a una lista vacía indica que el módulo no tiene API pública.

[...]

Los nombres importados siempre deben considerarse un detalle de implementación. Otros módulos no deben depender del acceso indirecto a dichos nombres importados a menos que sean una parte explícitamente documentada de la API del módulo contenedor, como os.path o un paquete __init__ módulo que expone la funcionalidad de los submódulos.

Además, como se señaló en otras respuestas, __all__ se usa para habilitar importación de comodines para paquetes:

La declaración de importación utiliza la siguiente convención: si un paquete está __init__.py el código define una lista llamada __all__, se toma como la lista de nombres de módulos que se deben importar cuando from package import * se encuentra.


7
2018-04-26 01:39



Respuesta corta

__all__ afecta from <module> import * declaraciones.

Respuesta larga

Considera este ejemplo:

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

En foo/__init__.py:

  • (Implícito) Si no definimos __all__, entonces from foo import * solo importará los nombres definidos en foo/__init__.py.

  • (Explícito) Si definimos __all__ = [], entonces from foo import * no importará nada

  • (Explícito) Si definimos __all__ = [ <name1>, ... ], entonces from foo import * solo importará esos nombres.

Tenga en cuenta que en el caso implícito, Python no importará nombres comenzando con _. Sin embargo, puede forzar la importación de dichos nombres usando __all__.

Puedes ver el documento de Python aquí.


2
2018-04-03 01:19