__all__ en Python

Hiten Kanwar 3 abril 2022
__all__ en Python

A medida que profundizamos en los paquetes y módulos, es posible que encontremos la variable __all__ configurada en diferentes archivos _init_.py.

Los archivos __init__.py son los archivos que hacen que Python trate los directorios como paquetes que contienen. Este archivo evita que los directorios con nombres similares, como cadenas, oculten módulos válidos que podrían aparecer más adelante en la ruta de búsqueda de un módulo.

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

Por lo tanto, __init__.py puede declarar las variables __all__ para un paquete.

Una lista de objetos públicos de ese módulo se da en la variable __all__. Es interpretado por el import *. Esta variable anula el valor predeterminado de ocultar todo lo que comienza con un guión bajo del espacio de nombres dado.

Por ejemplo,

__all__ = ["a", "b"]
c = 5
a = 10


def b():
    return "b"

Ahora importamos esto en el siguiente código.

from sample import *

print(a)  # will work fine
print(b)  # will work fine
print(c)  # will generate an error

En el ejemplo anterior, hemos utilizado import * para importar todos los objetos públicos del archivo sample.py a este archivo. Significa que este archivo importará y admitirá todos los objetos públicos del archivo sample.py.

Se importarán los objetos a y b y el nuevo código funcionará perfectamente donde se utilicen estos objetos. El problema surge al utilizar el tercer objeto, c. Ese objeto nunca se importa al nuevo archivo ya que no es un objeto público, como no es parte de la variable __all__. Entonces, esta parte del código generará un error.

Hay una alternativa a esto. Por defecto, Python asumirá la responsabilidad de exportar todos los nombres que no comiencen con un guión bajo _. Y ciertamente se podría confiar en este mecanismo. En la biblioteca estándar de Python, algunos paquetes se basan en esto, pero para hacerlo, asignan un alias a sus importaciones, por ejemplo, os como _os, sys como _sys, etc.

Usar la convención _ es más práctico ya que elimina la redundancia de nombrar los nombres repetidamente. Pero agrega la redundancia para las importaciones (si tiene muchas), y es más fácil olvidarse de hacer esto de manera consistente.

Muchos paquetes de la biblioteca estándar usan __all__. Tiene sentido usar la convención de prefijo _ en lugar de __all__ cuando todavía está en modo de desarrollo inicial y no tiene usuarios y está constantemente ajustando su API. Tal vez haya algunos usuarios, pero uno tiene pruebas unitarias que cubren la API y aún actualizan y agregan activamente a la API y ajustan el desarrollo.