__main__
— Top-level code environment¶
En Python, el nombre especial __main__
es utilizado para dos constructos importantes:
el nombre del entorno de máximo nivel del programa, que puede ser verificado usando la expresión
__name__=='__main__'
; yel archivo
__main__.py
en paquetes de Python.
Ambos de estos mecanismos están relacionados con módulos de Python; como los usuarios interactúan con ellos y como ellos interactúan entre sí. Están explicados en detalle más abajo. Si estás empezando con los módulos de Python, mira la sección tutorial Módulos para una introducción.
__name__ == '__main__'
¶
Cuando un módulo o paquete de Python es importado, __name__
es asignado al nombre del módulo. Normalmente, este es el nombre del archivo de Python sin la extensión .py
:
>>> import configparser
>>> configparser.__name__
'configparser'
Si el archivo es parte de un paquete, __name__
también incluirá la ruta del paquete padre:
>>> from concurrent.futures import process
>>> process.__name__
'concurrent.futures.process'
Sin embargo, si el módulo es ejecutado en el entorno de código de máximo nivel, su __name__
se le asigna el valor del string '__main__'
.
¿Qué es el «entorno de código de máximo nivel»?¶
__main__
es el nombre del entorno en el cual se ejecuta el código de máximo nivel. «Código de máximo nivel» es el primer módulo de Python especificado por el usuario que empieza a ejecutarse. Es «de máximo nivel» porque importa todos los demás módulos que necesita el programa. A veces «código de máximo nivel» es llamado un punto de entrada a la aplicación.
El entorno de código de máximo nivel puede ser:
el ámbito de un intérprete interactivo:
>>> __name__ '__main__'
el módulo de Python pasado al intérprete de Python como un argumento de archivo:
$ python helloworld.py Hello, world!
el módulo o paquete de Python pasado al interprete de Python con el argumento
-m
:$ python -m tarfile usage: tarfile.py [-h] [-v] (...)
Código de Python leído por el interprete desde input estándar:
$ echo "import this" | python The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
Código de Python pasado al intérprete Python con el argumento
-c
:$ python -c "import this" The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. ...
En cada una de estas situaciones, al __name__
del módulo de máximo nivel se le asigna el valor '__main__'
.
En consecuencia, un módulo puede descubrir si se está ejecutando o no en el ámbito principal al verificar su propio __name__
, lo cual permite un vocablo común para ejecutar código condicionalmente cuando el módulo no es inicializado desde una declaración de importado:
if __name__ == '__main__':
# Execute when the module is not initialized from an import statement.
...
Ver también
Para una vista más detallada de como __name__
es asignado en todas las situaciones, ver la sección tutorial Módulos.
Uso idiomático¶
Algunos módulos contienen código que está pensado para uso de script solamente, como para interpretar argumentos de línea de comando u obtener datos de la entrada estándar. Cuando un módulo como este fuese importado desde un módulo distinto, por ejemplo para realizar una prueba unitaria, el código del script se ejecutaría involuntariamente.
Aquí es donde es útil usar el código de bloque if __name__=='__main__'
. El código dentro desde bloque no se ejecutará a menos que el módulo se ejecute en el entorno de máximo nivel.
Poner cuantas menos declaraciones posible en el bloque debajo de if __name__=='__main__'
puede mejorar la claridad y validez del código. Mas a menudo, la función llamada main
encapsula el comportamiento principal del programa:
# echo.py
import shlex
import sys
def echo(phrase: str) -> None:
"""A dummy wrapper around print."""
# for demonstration purposes, you can imagine that there is some
# valuable and reusable logic inside this function
print(phrase)
def main() -> int:
"""Echo the input arguments to standard output"""
phrase = shlex.join(sys.argv)
echo(phrase)
return 0
if __name__ == '__main__':
sys.exit(main()) # next section explains the use of sys.exit
Note que si el módulo no encapsulase el código dentro de la función main
pero en vez lo pusiese directo dentro del bloque if __name__=='__main__'
, la variable phrase
sería global al módulo entero. Esto está propenso a generar errores ya que otras funciones dentro del módulo pudiesen estar usando involuntariamente la variable global en lugar de un nombre local. Una función main
resuelve este problema.
Usar una función main
tiene el beneficio añadido de que la función echo
está aislada y es importable en otros sitios. Cuando echo.py
es importado, las funciones echo
y main
serán definidas, pero ninguna de ellas será llamada porque __name!='__main__'
.
Consideraciones de empaquetado¶
Las funciones main
se utilizan a menudo para crear líneas de comando al especificarlas como puntos de entrada para scripts de terminal. Cuando esto se hace, pip inserta la llamada de la función a un script plantilla, donde el valor retornado de main
se pasa a sys.exit()
. Por ejemplo:
sys.exit(main())
Dado que la llamada a main
está dentro de sys.exit()
, la expectativa es que tu función devolverá un valor aceptable como una entrada a sys.exit()
; típicamente, un int o None
(que se retorna implícitamente si tu función no tiene una declaración de retorno).
Al seguir pro-activamente esta convención nosotros mismo, nuestro módulo tendrá el mismo comportamiento cuando se ejecuta directamente (es decir, python echo.py
) que si luego lo empaquetamos como un punto de entrada de script de terminal en un paquete instalable mediante pip.
En particular, ten cuidado al devolver cadenas de texto con tu función main
. sys.exit()
interpretará un argumento de cadena de texto como un mensaje de fallo, entonces tu programa tendrá un código de salida de 1
, indicando fallo, y la cadena de texto será escrita a sys.stderr
. El ejemplo echo.py
de antes muestra como usar la convención sys.exit(main())
.
Ver también
Python Packaging User Guide contiene una colección de tutoriales y referencias sobre como distribuir e instalar paquetes de Python con herramientas modernas.
__main__.py
en paquetes de Python¶
Si no estás familiarizado con paquetes de Python, ver la sección Paquetes del tutorial. Comúnmente, el archivo __main__.py
es utilizado para proveer una interfaz de línea de comando para un paquete. Considera el siguiente paquete hipotético, «bandclass»:
bandclass
├── __init__.py
├── __main__.py
└── student.py
__main__.py
será ejecutado cuando el paquete sea invocado directamente desde la línea de comandos usando el indicador -m
. Por ejemplo:
$ python -m bandclass
Este comando causará que __main__.py
se ejecute. El como se use este mecanismo dependerá de la naturaleza del paquete que estás escribiendo, pero en este caso hipotético, puede tener sentido permitir que el profesor busque estudiantes:
# bandclass/__main__.py
import sys
from .student import search_students
student_name = sys.argv[1] if len(sys.argv) >= 2 else ''
print(f'Found student: {search_students(student_name)}')
Note que from .student import search_students
es un ejemplo de una importación relativa. Este estilo de importación debe ser utilizado cuando se hace referencia a módulos dentro de un paquete. Para más detalles, ver Referencias internas en paquetes en la sección Módulos del tutorial.
Uso idiomático¶
Los contenidos de __main__.py
no están típicamente acotados dentro de bloques if __name__=='__main__'
. En cambio, esos archivos se mantienen cortos e importan funciones para ejecutar desde otros módulos. A esos otros módulos se les puede fácilmente realizar pruebas unitarias y son apropiadamente re-utilizables.
Si se usa, un bloque if __name__=='__main__'
seguirá funcionando como se espera para un archivo __main__.py
dentro de un paquete, porque su atributo __name__
incluirá la ruta del paquete si es importado:
>>> import asyncio.__main__
>>> asyncio.__main__.__name__
'asyncio.__main__'
This won’t work for __main__.py
files in the root directory of a
.zip
file though. Hence, for consistency, a minimal __main__.py
without a __name__
check is preferred.
Ver también
En venv
puedes conseguir un ejemplo de un paquete con un __main__.py
minimalista en la librería estándar. No contiene un bloque if __name__=='__main__'
. Lo puedes invocar con python -m venv [directorio]
.
Ver runpy
para más detalles sobre el indicador -m
para el interprete ejecutable.
Ver zipapp
para más información sobre como ejecutar aplicaciones empaquetadas como archivos .zip. En este caso Python busca un archivo __main__.py
en el directorio raíz del archivo comprimido.
import __main__
¶
Independientemente de con cual módulo se ha iniciado un programa de Python, otros módulos que están siendo ejecutados dentro del mismo programa pueden importar el ámbito del entorno de máximo nivel (namespace) al importar el módulo __main__
. Esto no importa un archivo __main__.py
pero en su lugar cualquier módulo que recibió el nombre especial '__main__'
.
Acá hay un módulo ejemplo que consume el nombre de espacio __main__
:
# namely.py
import __main__
def did_user_define_their_name():
return 'my_name' in dir(__main__)
def print_user_name():
if not did_user_define_their_name():
raise ValueError('Define the variable `my_name`!')
if '__file__' in dir(__main__):
print(__main__.my_name, "found in file", __main__.__file__)
else:
print(__main__.my_name)
Ejemplo del uso de este módulo puede ser:
# start.py
import sys
from namely import print_user_name
# my_name = "Dinsdale"
def main():
try:
print_user_name()
except ValueError as ve:
return str(ve)
if __name__ == "__main__":
sys.exit(main())
Si ahora iniciamos nuestro programa el resultado sería así:
$ python start.py
Define the variable `my_name`!
El código de salida del programa sería 1, indicando un error. Des-comentando la línea con my_name = "Dinsdale"
arregla el programa y ahora sale con un código de estado 0, indicando éxito:
$ python start.py
Dinsdale found in file /path/to/start.py
Note que importar __main__
no causa ningún problema de involuntariamente ejecutar código de máximo nivel que ha sido pensado para uso por scripts que es puesto en el bloque if __name__=="__main__"
del módulo start
. ¿Por qué funciona esto?
Python inserta un módulo __main__
vacío en sys.modules
al inicio del intérprete, y lo puebla ejecutando código de máximo nivel. En nuestro ejemplo este es el módulo start
que corre línea a línea e importa namely
. A su vez, namely
importa __main__
(que es en verdad start
). ¡Es un ciclo de importado! Afortunadamente, como el módulo parcialmente poblado __main__
está presente en sys.modules
, Python pasa eso a namely
. Ver Special considerations for __main__ en la referencia del sistema para información detallada de como funciona.
El REPL Python es otro ejemplo de un «entorno de máximo nivel», por lo tanto, cualquier cosa definida en el REPL se hace parte del ámbito __main__
:
>>> import namely
>>> namely.did_user_define_their_name()
False
>>> namely.print_user_name()
Traceback (most recent call last):
...
ValueError: Define the variable `my_name`!
>>> my_name = 'Jabberwocky'
>>> namely.did_user_define_their_name()
True
>>> namely.print_user_name()
Jabberwocky
Note que en este caso el ámbito __main__
no contiene un atributo __file__
ya que es interactivo.
El ámbito __main__
es utilizado en la implementación de pdb
y rlcompleter
.