namespace else python syntax namespaces

else - python class



¿Alguien puede explicar__all__ en Python? (9)

Explica __all__ en Python?

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

¿Qué hace esto?

¿Qué hace __all__ ?

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 tener la expectativa de que no cambiará.

También tendrá efectos programáticos:

import *

__all__ en un módulo, por ejemplo, module.py :

__all__ = [''foo'', ''Bar'']

significa que cuando import * del módulo, solo se importan los nombres en __all__ :

from module import * # imports foo and Bar

Herramientas de documentacion

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

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

De la docs :

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

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

Así que __init__.py puede declarar __all__ para un paquete .

Gestionando una API:

Un paquete generalmente está formado por módulos que pueden importarse entre sí, pero que necesariamente están vinculados con un archivo __init__.py . Ese archivo es lo que hace que el directorio sea un paquete real de Python. Por ejemplo, digamos que tienes lo siguiente:

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

en el __init__.py escribes:

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 otra persona puede usar cuando importan su paquete, así:

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

Y no tendrán todos los otros nombres que usó al crear sus módulos que abarrotan el espacio de nombres del package .

__all__ en __init__.py

Después de más trabajo, tal vez haya decidido que los módulos son demasiado grandes y deben dividirse. Así que 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 declara un __all__ , por ejemplo, en el módulo_1:

from foo_implementation import * __all__ = [''foo'']

Y el módulo_2 de __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 __init__.py , por ejemplo, en module_2:

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

Y si no está listo para publicar Baz en la API de nivel superior, en su nivel superior __init__.py podría 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 son conscientes de la disponibilidad de Baz , pueden usarlo:

import package package.Baz()

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 de máxima audiencia:

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

Prefijando _ contra __all__ :

De forma predeterminada, Python exportará todos los nombres que no comiencen con un _ . Ciertamente podrías confiar en este mecanismo. De hecho, algunos paquetes en la biblioteca estándar de Python dependen de esto, pero para hacerlo, alias sus importaciones, por ejemplo, en ctypes/__init__.py :

import os as _os, sys as _sys

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 de manera consistente, y lo último que quiere es tener que soportar indefinidamente algo que pretendía ser solo un detalle de implementación, solo porque olvidaste el prefijo de una _ al nombrar una función.

Personalmente escribo un __all__ principio 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 usar.

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

Cuando evitar __all__ tiene sentido

Tiene sentido adherirse a la convención de prefijos en lugar de __all__ cuando:

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

Un decorador de export

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. Podríamos usar un decorador para resolver este problema.

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

Entonces, por ejemplo, en una biblioteca de utilidades, 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__ , haces 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 si se ejecuta como principal o importado por otra función.

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

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

$ 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

He estado usando Python más y más, y sigo viendo la variable __all__ establecida en diferentes archivos __init__.py . ¿Alguien puede explicar qué hace esto?


Respuesta corta

__all__ afecta a from <module> import * declaraciones from <module> import *

Respuesta larga

Considera este ejemplo:

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

En foo/__init__.py :

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

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

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

Tenga en cuenta que, en el caso implícito, python no importará nombres que empiecen por _ . Sin embargo, puede forzar la importación de dichos nombres utilizando __all__ .

Puedes ver el documento de Python aquí .


__all__ personaliza el asterisco from <module> import *

__all__ personaliza el asterisco from <package> import *

Un module es un archivo .py destinado a ser importado.

Un module es un directorio con un archivo __init__.py . Un paquete generalmente contiene módulos.

""" cheese.py - an example module """ __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 . [ @AaronHall ] Además, pydoc los reconoce. [ @Longpoke ]

desde el módulo de importación *

Vea cómo el swiss y el cheddar son traídos al espacio de nombres local, pero no a 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.

Las importaciones sin * no se ven afectadas por __all__

módulo de importación

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

desde el módulo de importación de nombres

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

módulo de importación como nombre local

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

En el archivo __init__.py 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 el * al importar comodines desde el paquete. [ @MartinStettner ]

Aquí hay un extracto del conector MySQL de Python __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 con comodines ... deben evitarse, ya que [confunden] a los lectores y muchas herramientas automatizadas.

[ PEP 8 , @ToolmakerSteve]


De (un no oficial) Wiki de referencia de Python :

Los nombres públicos definidos por un módulo se determinan revisando 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__ se consideran todos públicos y deben existir. 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á pensado para evitar la exportación accidental de elementos que no forman parte de la API (como los módulos de biblioteca que se importaron y utilizaron dentro del módulo).


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


Solo estoy agregando esto para ser precisos:

Todas las demás respuestas se refieren a módulos . La pregunta original mencionó explícitamente __all__ en los archivos __init__.py , por lo que se trata de paquetes de python.

En general, __all__ solo entra en juego cuando se utiliza la variante from xxx import * de la declaración de import . 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 here en detalle.

En resumen, __all__ en el 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 ). Así que __all__ especifica todos los módulos que se __all__ e importarán en el espacio de nombres actual cuando usemos from package import * .

La gran diferencia es que cuando omite la declaración de __all__ en el __all__ de un paquete, la declaración from package import * no importará nada en absoluto (con las excepciones explicadas en la documentación, vea 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.


También cambia lo que pydoc mostrará:

módulo1.py

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

módulo2.py

__all__ = [''a'', ''b''] a = "A" b = "B" c = "C"

$ pydoc module1

Help on module module1: NAME module1 FILE module1.py DATA a = ''A'' b = ''B'' c = ''C''

$ pydoc module2

Help on module module2: NAME module2 FILE module2.py DATA __all__ = [''a'', ''b''] a = ''A'' b = ''B''

Declaro __all__ en todos mis módulos, además de subrayar los detalles internos, estos realmente ayudan cuando utilizo cosas que nunca ha usado antes en sesiones de intérpretes en vivo.


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

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

__all__ = [''bar'', ''baz''] waz = 5 bar = 10 def baz(): return ''baz''

Estos símbolos pueden ser importados 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__ anterior 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 comiencen 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 comportamiento from <module> import * solamente. Los miembros que no se mencionan en __all__ todavía son accesibles desde fuera del módulo y se pueden importar con from <module> import <member> .


__all__ se utiliza para documentar la API pública de un módulo de Python. Aunque es opcional, debe usarse __all__ .

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

Los nombres públicos definidos por un módulo se determinan revisando 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__ se consideran todos públicos y deben existir. 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á pensado para evitar la exportación accidental de elementos que no forman parte de la API (como los módulos de biblioteca que se importaron y utilizaron dentro del módulo).

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

Para soportar mejor la introspección, los módulos deben declarar explícitamente los nombres en su API pública usando el atributo __all__ . La configuración de __all__ en una lista vacía indica que el módulo no tiene una 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 documentada explícitamente de la API del módulo que lo contiene, como os.path o el módulo __init__ un paquete que expone la funcionalidad de los submódulos.

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

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