He estado usando Python cada vez más, y sigo viendo la variable __all__establecida en diferentes __init__.pyarchivos. ¿Alguien puede explicar qué hace esto?
python
syntax
namespaces
varikin
fuente
fuente

__all__si__all__está presente, no están exactamente ocultos; pueden verse y accederse perfectamente normalmente si conoce sus nombres. Solo en el caso de una "importación *", que de todos modos no se recomienda, la distinción tiene algún peso.import *(como, por ejemplotk). Una buena pista si este es el caso es la presencia de__all__o nombres que comienzan con un guión bajo en el código del módulo.tkse publicaran hoy (o incluso en 2012), la práctica recomendada sería usarfrom tk import *. Creo que la práctica se acepta por inercia, no por diseño intencional.Vinculado, pero no mencionado explícitamente aquí, es exactamente cuando
__all__se usa. Es una lista de cadenas que definen qué símbolos en un módulo se exportarán cuandofrom <module> import *se usen en el módulo.Por ejemplo, el siguiente código de forma
foo.pyexplícita exporta los símbolosbarybaz:Estos símbolos pueden importarse así:
Si
__all__se comenta lo anterior, este código se ejecutará hasta su finalización, ya que el comportamiento predeterminado deimport *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/tutorial/modules.html#importing-from-a-package
NOTA: solo
__all__afecta elfrom <module> import *comportamiento. Los miembros que no se mencionan__all__aún son accesibles desde fuera del módulo y se pueden importar confrom <module> import <member>.fuente
print(baz())?print(baz)imprime algo parecido a<function baz at 0x7f32bc363c10>mientras queprint(baz())imprimebaz¿Qué
__all__hacer?Declara los nombres semánticamente "públicos" de un módulo. Si hay un nombre
__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, por ejemplomodule.py:significa que,
import *desde el módulo, solo se importan los nombres en el__all__:Herramientas de documentación
Las herramientas de autocompletado de código y documentación pueden (de hecho, deberían) también inspeccionar
__all__para determinar qué nombres mostrar como disponibles desde un módulo.__init__.pyconvierte un directorio en un paquete de PythonDe los documentos :
Entonces
__init__.pypuede declarar el__all__para un paquete .Administrar una API:
Un paquete generalmente está compuesto por módulos que pueden importarse entre sí, pero que necesariamente están vinculados con un
__init__.pyarchivo. Ese archivo es lo que hace que el directorio sea un paquete de Python real. Por ejemplo, supongamos que tiene los siguientes archivos en un paquete:Creemos estos archivos con Python para que pueda seguirlos: puede pegar lo siguiente en un shell de Python 3:
Y ahora ha presentado una API completa que otra persona puede usar cuando importan su paquete, así:
Y el paquete no tendrá todos los demás detalles de implementación que usó al crear sus módulos abarrotando el
packageespacio de nombres.__all__en__init__.pyDespués de más trabajo, tal vez haya decidido que los módulos son demasiado grandes (¿como muchos miles de líneas?) Y deben dividirse. Entonces haces lo siguiente:
Primero haga los directorios de subpaquete con los mismos nombres que los módulos:
Mover las implementaciones:
cree
__init__.pys para los subpaquetes que declaran el__all__para cada:Y ahora todavía tiene la API aprovisionada a nivel de paquete:
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
__init__.py, por ejemplo, en module_2:Y si no está listo para publicar
Bazen la API de nivel superior, en su nivel superior__init__.pypodría tener:y si sus usuarios conocen la disponibilidad de
Baz, pueden usarla:pero si no lo saben, otras herramientas (como pydoc ) no les informarán.
Más tarde puede cambiar eso cuando
Bazesté listo para el horario estelar:Prefijo
_versus__all__:Por defecto, Python exportará todos los nombres que no comiencen con un
_. Ciertamente podría confiar en este mecanismo. Algunos paquetes de la biblioteca estándar de Python, de hecho, no se basan en esto, pero para hacerlo, ellos alias de sus importaciones, por ejemplo, enctypes/__init__.py:Usar 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, solo porque olvidó prefijar un_al nombrar una función.Personalmente, escribo una de las
__all__primeras etapas de mi ciclo de vida de desarrollo para módulos para que otras personas que puedan usar mi código sepan qué deben usar y qué no.La mayoría de los paquetes en la biblioteca estándar también usan
__all__.Cuando evitar
__all__tiene sentidoTiene sentido apegarse a la
_convención de prefijo en lugar de__all__cuando:Un
exportdecoradorLa desventaja de usar
__all__es que tiene que escribir los nombres de las funciones y clases que se exportan dos veces, y la información se mantiene separada de las definiciones. nos podía usar un decorador para resolver este problema.La idea de un decorador de exportación de este tipo surgió 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 retirarse: solo tendrá que agregar manualmente los nombres nuevamente en el
__all__Entonces, por ejemplo, en una biblioteca de utilidades, definiría el decorador:
y luego, donde definirías un
__all__, haces esto:Y esto funciona bien si se ejecuta como principal o importado por otra función.
Y el aprovisionamiento de API
import *también funcionará:fuente
@exportdecorador.__init__.pyy el uso de__all____all__es correcto.__all__también, pero diría que tienes una API inestable ... Esto sería algo para tener algunas pruebas de aceptación exhaustivas.module_1ymodule_2; ¿Está bien incluir un explícitodel module_1en__init__.py? ¿Me equivoco al pensar que esto vale la pena?Solo estoy agregando esto para ser precisos:
Todas las demás respuestas se refieren a módulos . La pregunta original mencionada explícitamente
__all__en los__init__.pyarchivos, por lo que se trata de paquetes de Python .En general,
__all__solo entra en juego cuando se utiliza lafrom xxx import *variante de laimportdeclaración. Esto se aplica tanto a los paquetes como a los módulos.El comportamiento de los módulos se explica en las otras respuestas. El comportamiento exacto de los paquetes se describe aquí en detalle.
En resumen,
__all__a nivel de paquete hace aproximadamente lo mismo que para los módulos, excepto que trata con módulos dentro del paquete (en contraste con la especificación de nombres dentro del módulo ). Por lo tanto,__all__especifica todos los módulos que se cargarán e importarán en el espacio de nombres actual cuando lo usemosfrom package import *.La gran diferencia es que cuando omite la declaración de
__all__un paquete__init__.py, la declaraciónfrom package import *no importará nada (con las excepciones explicadas en la documentación, consulte el enlace anterior).Por otro lado, si omite
__all__en un módulo, la "importación destacada" importará todos los nombres (que no comiencen con un guión bajo) definidos en el módulo.fuente
from package import *aún importará todo lo definido en__init__.py, incluso si no hayall. La diferencia importante es que sin__all__él no importará automáticamente ningún módulo definido en el directorio del paquete.También cambia lo que mostrará pydoc:
module1.py
module2.py
$ pydoc module1
Ayuda sobre el módulo module1: NOMBRE módulo 1 ARCHIVO module1.py DATOS a = 'A' b = 'B' c = 'C'$ pydoc module2
Ayuda sobre el módulo module2: NOMBRE módulo2 ARCHIVO module2.py DATOS __todos__ = ['a', 'b'] a = 'A' b = 'B'Declaro
__all__en todos mis módulos, así como subrayar los detalles internos, estos realmente ayudan cuando se usan cosas que nunca antes has usado en sesiones de intérpretes en vivo.fuente
__all__personaliza*enfrom <module> import *__all__personaliza*enfrom <package> import *Un módulo es un
.pyarchivo destinado a ser importado.Un paquete es un directorio con un
__init__.pyarchivo. Un paquete generalmente contiene módulos.MÓDULOS
__all__les permite a los humanos conocer las características "públicas" de un módulo . [ @AaronHall ] Además, pydoc los reconoce. [ @Longpoke ]desde la importación del módulo *
Vea cómo
swissycheddarse introducen en el espacio de nombres local, pero nogouda:Sin
__all__, cualquier símbolo (que no comience con un guión bajo) habría estado disponible.Las importaciones sin
*no se ven afectadas por__all__módulo de importación
de los nombres de importación de módulos
módulo de importación como nombre local
PAQUETES
En el
__init__.pyarchivo de un paquete__all__hay 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 la*importación de comodines desde el paquete. [ @MartinStettner ]Aquí hay un extracto del conector Python MySQL
__init__.py:El caso predeterminado, un asterisco sin
__all__un paquete , es complicado, porque el comportamiento obvio sería costoso: usar el sistema de archivos para buscar todos los módulos en el paquete. En cambio, en mi lectura de los documentos, solo se importan los objetos definidos en__init__.py:[ PEP 8 , @ToolmakerSteve]
fuente
from <package> import *sin__all__en__init__.pyque está no importando cualquiera de los módulos .__init__.pyfuera un módulo . Pero no estoy seguro de que sea exacto, o en particular si se excluyen los objetos con subrayado subrayado. Además, separé más claramente las secciones sobre MÓDULOS y PAQUETES. ¿Tus pensamientos?De (Un No Oficial) Python Reference Wiki :
fuente
__all__se usa para documentar la API pública de un módulo de Python. Aunque es opcional,__all__debe usarse.Aquí está el extracto relevante de la referencia del lenguaje Python :
PEP 8 usa 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:Además, como se señaló en otras respuestas,
__all__se utiliza para habilitar la importación de comodines para paquetes :fuente
Respuesta corta
__all__afecta lasfrom <module> import *declaraciones.Respuesta larga
Considere este ejemplo:
En
foo/__init__.py:(Implícito) Si no definimos
__all__,from foo import *solo importaremos los nombres definidos enfoo/__init__.py.(Explícito) Si definimos
__all__ = [], entoncesfrom foo import *no importará nada.(Explícito) Si definimos
__all__ = [ <name1>, ... ],from foo import *solo importaremos esos nombres.Tenga en cuenta que, en el caso implícito, python no importará nombres que comiencen por
_. Sin embargo, puede forzar la importación de dichos nombres utilizando__all__.Puede ver el documento de Python aquí .
fuente
__all__afecta cómofrom foo import *funcionaEl código que está dentro del cuerpo de un módulo (pero no en el cuerpo de una función o clase) puede usar un asterisco (
*) en unafromdeclaración:Las
*solicitudes de que todos los atributos del módulofoo(excepto los que comienzan con guiones bajos) se unan como variables globales en el módulo de importación. Cuandofootiene un atributo__all__, el valor del atributo es la lista de los nombres que están vinculados por este tipo defromdeclaración.Si
fooes un paquete y__init__.pydefine una lista llamada__all__, se considera que es la lista de nombres de submódulos que deben importarse cuandofrom foo import *se encuentran. Si__all__no está definido, la instrucciónfrom foo import *importa los nombres definidos en el paquete. Esto incluye cualquier nombre definido (y submódulos cargados explícitamente) por__init__.py.Tenga en cuenta que
__all__no tiene que ser una lista. Según la documentación de laimportdeclaración , si está definida,__all__debe ser una secuencia de cadenas que son nombres definidos o importados por el módulo. Por lo tanto, también puede usar una tupla para ahorrar memoria y ciclos de CPU. Simplemente no olvide una coma en caso de que el módulo defina un solo nombre público:Consulte también ¿Por qué es malo "importar *"?
fuente
Esto se define en PEP8 aquí :
PEP8 proporciona convenciones de codificación para el código de Python que comprende la biblioteca estándar en la distribución principal de Python. Cuanto más sigas esto, más cerca estarás de la intención original.
fuente