70

Es común encontrarnos código con esta forma:

def hacer_algo():
    print("algo")

if __name__ == "__main__":
    hacer_algo()

En lugar de, por ejemplo:

def hacer_algo():
    print("algo")

hacer_algo()

También notamos que la variable __name__ no es inicializada por nosotros, pero existe en el entorno.

  • ¿Cuál es la diferencia?
  • ¿Por qué preferir uno sobre el otro?
  • ¿Qué es y cómo funciona?
IDis31
  • 1,076
  • 2
  • 10
  • 14

4 Answers4

107

Esto está íntimamente ligado al modo de funcionamiento del intérprete Python:

  • Cuando el intérprete lee un archivo de código, ejecuta todo el código global que se encuentra en él. Esto implica crear objetos para toda función o clase definida y variables globales.

  • Todo módulo (archivo de código) en Python tiene un atributo especial llamado __name__ que define el espacio de nombres en el que se está ejecutando. Es usado para identificar de forma única un módulo en el sistema de importaciones.

  • Por su parte "__main__" es el nombre del ámbito en el que se ejecuta el código de nivel superior (tu programa principal).

  • El intérprete pasa el valor del atributo __name__ a la cadena '__main__' si el módulo se está ejecutando como programa principal (cuando lo ejecutas llamando al intérprete en la terminal con python my_modulo.py, haciendo doble click en él, ejecutándolo en el intérprete interactivo, etc ).

  • Si el módulo no es llamado como programa principal, sino que es importado desde otro módulo, el atributo __name__ pasa a contener el nombre del archivo en si.

Aquí tienes la documentación oficial.

Es decir, si tienes un archivo llamado mi_modulo.py, si lo ejecutamos como programa principal el atributo __name__ será '__main__', si lo usamos importándolo desde otro módulo (import mi_modulo) el atributo __name__ será igual a 'mi_modulo'.

Básicamente, lo que haces usando if __name__ == “__main__”: es ver si el módulo ha sido ejecutado directamente o no (importado). Si se ha ejecutado como programa principal se ejecuta el código dentro del condicional.

Una de las razones para hacerlo es que, a veces, se escribe un módulo (un archivo .py) que se puede ejecutar directamente pero que, alternativamente, también se puede importar y reutilizar sus funciones, clases, métodos, etc en otro módulo.

En frameworks gráficos por ejemplo es común generar un ejemplo de uso del widget o widgets definidos en ese módulo que sirve de ejemplo de uso y para testear el propio módulo. Si ejecutas el módulo tendremos una interfaz gráfica de ejemplo, pero ni que decir tiene que cuando importamos el módulo para usar el widget no queremos que nos aparezca una ventanita por ahí por amor al arte. Un ejemplo real en el framework Kivy:

Con el uso del condicional conseguimos que la ejecución sea diferente al ejecutar el módulo directamente que al importarlo desde otro módulo. Todo lo que hay dentro del condicional será completamente ignorado por el interprete cuando se importa el módulo, pero no cuando se ejecute como módulo principal.

Para ver como funciona puedes probar algún código (siguiendo tu propio ejemplo):

Creas un módulo al que llamaremos mi_modulo.py:

print("¡Hola desde mi_modulo.py!")

def hacer_algo():
    print("¡Soy una función y hago algo!")

if __name__ == "__main__":
    print('Ejecutando como programa principal')
    hacer_algo()

print("¡Adiós desde mi_módulo.py!")  # Debajo del condicional pero fuera del mismo

En la misma carpeta creas otro módulo al que llamaremos principal.py

import mi_modulo

print("¡Hola desde principal.py!")
mi_modulo.hacer_algo()
print("¡Adiós desde principal.py!")

Si ejecutas el script mi_modulo.py directamente:

$ python mi_modulo.py

el valor de __name__ será "__main__" y se ejecutará el bloque que hay dentro del if __name__ == “__main__”::

¡Hola desde mi_modulo.py!
Ejecutando como programa principal
¡Soy una función y hago algo!
¡Adiós desde mi_modulo.py!

Si ejecutamos el archivo principal.py que usa mi_modulo.py importándolo no se cumple la condición if __name__ == “__main__” por lo que solo se ejecuta el código global (el print inicial y se crea el objeto función hacer_algo en memoria). La función solo se ejecuta cuando la llamamos desde el módulo principal:

¡Hola desde mi_modulo.py!
¡Adiós desde mi_modulo.py!
¡Hola desde principal.py!
¡Soy una función y hago algo!
¡Adiós desde principal.py!

Ahora vamos a cambiar el script mi_modulo.py por:

print("¡Hola desde mi_modulo.py!")

def hacer_algo():
    print("¡Soy una función y hago algo!")

hacer_algo()
print("¡Adiós desde mi_modulo.py!"))

Si lo ejecutamos como programa principal el resultado es el mismo que antes, pero si ejecutamos ahora principal.py nos sale esto:

¡Hola desde mi_modulo.py!
¡Soy una función y hago algo!
¡Adiós desde mi_modulo.py!
¡Hola desde principal.py!
¡Soy una función y hago algo!
¡Adiós desde principal.py!

Lo que pasa es que al importar ejecutamos todo el código del módulo importado, incluyendo la llamada a la función que ahora no está envuelta en el condicional. Una vez importado el módulo principal llama a la función importada de nuevo.

En definitiva, las dos formas que pones son válidas si ejecutas el script siempre como programa principal, si lo usas también importándolo no sueles querer que se ejecute código si no llamas a una función tu mismo y esa es la razón de usar if __name__ == “__main__”:

FJSevilla
  • 55,603
  • 7
  • 35
  • 58
  • 1
    A modo de curiosidad, decir que si se usa el intérprete *bpython* para ejecutar los programas, el atributo `__name__` del módulo principal no es `"__main__"`, sino que es `"__console__"`. – Carlos A. Gómez Jul 09 '17 at 18:05
  • 2
    @CarlosA.Gómez gracias por el apunte, la verdad es que no conocía bpython ("nunca te irás a dormir sin saber algo nuevo"), voy a informarme a ver que ofrece :). Supongo que existen más variantes a la forma estándar que usa CPython (aunque todas siguen el mismo principio), otra que se me ocurre es al usar Kivy en Android, donde se usa `"__android__"`. Saludos. – FJSevilla Jul 09 '17 at 18:23
  • 1
    Genial, gracias, tampoco sabía lo de android. *Bpython* es más una interfaz mejorada en la terminal al intérprete Python que un intérprete en sí mismo. Aquí te paso el enlace: https://bpython-interpreter.org/ – Carlos A. Gómez Jul 09 '17 at 18:28
8

la instrucción if, del tipo:

if __name__ == “__main__”:
    # (bloque cosas dentro)

sirve para aislar o desacoplar la ejecución del (bloque de cosas dentro) dentro de un programa (condición true), a cuando se importa totalmente dicho programa en otro.

En ese caso, al ejecutar este otro, no se ejecutará el (bloque de cosas dentro) por tener condición false.

Así permito realizar cosas distintas con el mismo programa (directo vs importado).

Mariano
  • 23,777
  • 20
  • 70
  • 102
user37950
  • 81
  • 1
  • 2
5

Es la funcion principal del programa se utiliza para inicializar el programa para ello simplemente haces lo siguiente desde la cmd:

python tuejemplo.py

Y el programa se inicializa y ejecuta. Por otro lado, porque utilizar este método porque puedes arrancarlo o cuando quieres agregarlo como módulo entonces el programa no se arrancará yo pienso que esa es la unica diferencia.

Perl
  • 747
  • 1
  • 15
  • 34
3

Saludos a todos en la comunidad, yo voy a aportar mi granito de arena y explicarlo lo mas simple posible ya que entiendo a muchas personas que como yo en su momento no habia podido entender esta sentencia o mejor dicho esta condicion.

if __ name__ == "__ main__":

Esta condicion simplemente hace una consulta para verificar si el archivo que se esta ejecutando es el archivo principal o raiz del programa. En Python el metodo __ name__ es el nombre de tu archivo Ejemplo: calculadora.py >> ella tomara __ name__ el nombre de tu archivo .py y lo comparara con el __ main__ que siempre sera para python el archivo principal, el archivo con mayor gerarquia.

Pero seguramente te preguntaras que sentido tiene? para que voy a perder tiempo en crear una condicion si quiero que se ejecute el programa y ya!!

La respuesta a esto esta en que imaginemos una aplicacion con miles de archivos .py y te asignan ese proyecto que ya venia haciendo otra persona, como lograrias saber cual es tu archivo raiz? cual es el comienzo de todo? quizas comiences por uno que creas que era el raiz y no lo es!

Creo que esta seria una de las principales razones (de las tantas razones) porque usar if __ name__ == "__ main__"

No es obligatorio pero es una buena practica usarlo, espero haberme explicado bien y poder aportar mi granito de arena en la comunidad. Saludos a todos los colegas.