¿Cuál es el alcance de una variable inicializada en una declaración if?

266

Soy nuevo en Python, por lo que esta es probablemente una simple pregunta de alcance. El siguiente código en un archivo (módulo) de Python me confunde un poco:

if __name__ == '__main__':
    x = 1

print x

En otros idiomas en los que he trabajado, este código arrojaría una excepción, ya que la xvariable es local a la ifdeclaración y no debería existir fuera de ella. Pero este código se ejecuta e imprime 1. ¿Alguien puede explicar este comportamiento? ¿Todas las variables creadas en un módulo son globales / están disponibles para todo el módulo?

froadie
fuente
17
Otra peculiaridad que quizás no conozca: si la ifdeclaración anterior no es verdadera (es decir, no lo__name__ es , por ejemplo, cuando importa el módulo en lugar de ejecutarlo en el nivel superior), nunca se habrá vinculado, y la declaración posterior arrojará un . '__main__'xprint xNameError: name 'x' is not defined
Santa

Respuestas:

302

Las variables de Python tienen un alcance para la función, clase o módulo más interno en el que están asignadas. Los bloques de control como ify los whilebloques no cuentan, por lo que una variable asignada dentro de un iftodavía se limita a una función, clase o módulo.

(Funciones implícitas definidas por una expresión generadora o una lista / set / dict comprensión de hacer el recuento, al igual que las expresiones lambda. No se puede meter una instrucción de asignación en ninguno de ellos, pero los parámetros lambda y forobjetivos son cláusula de asignación implícita.)

Luke Maurer
fuente
1
@ chandr3sh docs.python.org/3/tutorial/…
Fakher Mokadem
105

Sí, están en el mismo "ámbito local", y en realidad un código como este es común en Python:

if condition:
  x = 'something'
else:
  x = 'something else'

use(x)

Tenga en cuenta que xno se declara o inicializa antes de la condición, como sería en C o Java, por ejemplo.

En otras palabras, Python no tiene ámbitos de nivel de bloque. Sin embargo, tenga cuidado con ejemplos como

if False:
    x = 3
print(x)

lo que claramente plantearía una NameErrorexcepción.

Eli Bendersky
fuente
42

El alcance en python sigue este orden:

  • Buscar en el ámbito local

  • Busque el alcance de cualquier función de cierre

  • Buscar el alcance global

  • Buscar en los empotrados

( fuente )

Tenga en cuenta que ify otras construcciones de bucle / ramificación no se enumeran: solo las clases, las funciones y los módulos proporcionan alcance en Python, por lo que cualquier cosa declarada en un ifbloque tiene el mismo alcance que cualquier cosa descifrada fuera del bloque. Las variables no se verifican en tiempo de compilación, por lo que otros idiomas arrojan una excepción. En python, siempre que la variable exista en el momento que lo requiera, no se lanzará ninguna excepción.

Daniel G
fuente
9

Como dijo Eli, Python no requiere declaración de variable. En C dirías:

int x;
if(something)
    x = 1;
else
    x = 2;

pero en Python la declaración es implícita, por lo que cuando se asigna a x, se declara automáticamente. Es porque Python se escribe dinámicamente; no funcionaría en un lenguaje estáticamente escrito, porque dependiendo de la ruta utilizada, una variable podría usarse sin ser declarada. Esto se detectaría en el momento de la compilación en un lenguaje tipado estáticamente, pero con un lenguaje tipado dinámicamente está permitido.

La única razón por la que un lenguaje de tipo estático se limita a tener que declarar variables fuera de las ifdeclaraciones debido a este problema. ¡Abraza la dinámica!

Drilldrick
fuente
9

A diferencia de lenguajes como C, una variable de Python está dentro del alcance de toda la función (o clase o módulo) donde aparece, no solo en el "bloque" más interno. Es como si declaraste int xen la parte superior de la función (o clase, o módulo), excepto que en Python no tienes que declarar variables.

Tenga en cuenta que la existencia de la variable xse verifica solo en tiempo de ejecución, es decir, cuando llega a la print xdeclaración. Si __name__no igualar "__main__"a continuación, se podrían obtener una excepción: NameError: name 'x' is not defined.

Paul Stephenson
fuente
Las clases no crean un alcance; una variable "local" en una clase simplemente se agrega al dict de la clase en el momento de la creación.
chepner
3

Si. También es cierto para el foralcance. Pero no funciona, por supuesto.

En su ejemplo: si la condición en la ifdeclaración es falsa, xno se definirá sin embargo.

Olivier Verdier
fuente
2

está ejecutando este código desde la línea de comandos, por iflo tanto, las condiciones son verdaderas y xestán establecidas. Comparar:

>>> if False:
    y = 42


>>> y
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    y
NameError: name 'y' is not defined
SilentGhost
fuente
0

Y tenga en cuenta que, dado que los tipos de Python solo se verifican en tiempo de ejecución, puede tener un código como:

if True:
    x = 2
    y = 4
else:
    x = "One"
    y = "Two"
print(x + y)

Pero tengo problemas para pensar en otras formas en que el código funcionaría sin un error debido a problemas de tipo.

cowang
fuente