He estado usando Python cada vez más, y sigo viendo la variable __all__
establecida en diferentes __init__.py
archivos. ¿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.tk
se 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.py
explícita exporta los símbolosbar
ybaz
: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__.py
convierte un directorio en un paquete de PythonDe los documentos :
Entonces
__init__.py
puede 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__.py
archivo. 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
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 (¿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__.py
s 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
Baz
en la API de nivel superior, en su nivel superior__init__.py
podrí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
Baz
esté 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
export
decoradorLa 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
@export
decorador.__init__.py
y 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_1
ymodule_2
; ¿Está bien incluir un explícitodel module_1
en__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__.py
archivos, por lo que se trata de paquetes de Python .En general,
__all__
solo entra en juego cuando se utiliza lafrom xxx import *
variante de laimport
declaració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
$ pydoc module2
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
.py
archivo destinado a ser importado.Un paquete es un directorio con un
__init__.py
archivo. 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
swiss
ycheddar
se 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__.py
archivo 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__.py
que está no importando cualquiera de los módulos .__init__.py
fuera 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 unafrom
declaració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. Cuandofoo
tiene un atributo__all__
, el valor del atributo es la lista de los nombres que están vinculados por este tipo defrom
declaración.Si
foo
es un paquete y__init__.py
define 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 laimport
declaració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