No hubo una respuesta completa sobre el tiempo de Python3, así que hice una respuesta aquí. La mayor parte de lo que se describe aquí se detalla en la Resolución 4.2.2 de los nombres de la documentación de Python 3.
Como se proporciona en otras respuestas, hay 4 ámbitos básicos, el LEGB, para Local, Enclosing, Global y Builtin. Además de esos, hay un alcance especial, el cuerpo de la clase , que no comprende un alcance cerrado para los métodos definidos dentro de la clase; cualquier tarea dentro del cuerpo de la clase hace que la variable a partir de ahí esté vinculada en el cuerpo de la clase.
Especialmente, ninguna declaración de bloque, además de defy class, crea un alcance variable. En Python 2, la comprensión de la lista no crea un alcance variable, sin embargo, en Python 3 la variable de bucle dentro de las comprensiones de la lista se crea en un nuevo alcance.
Demostrar las peculiaridades del cuerpo de clase.
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
Por lo tanto, a diferencia del cuerpo de la función, puede reasignar la variable al mismo nombre en el cuerpo de la clase, para obtener una variable de clase con el mismo nombre; más búsquedas en este nombre resuelven la variable de clase en su lugar.
Una de las mayores sorpresas para muchos recién llegados a Python es que un forbucle no crea un alcance variable. En Python 2, las comprensiones de la lista tampoco crean un alcance (¡mientras que los generadores y las comprensiones de dict sí lo hacen!) En cambio, pierden el valor en la función o el alcance global:
>>> [ i for i in range(5) ]
>>> i
4
Las comprensiones se pueden usar como una manera astuta (o horrible, si lo desea) para hacer variables modificables dentro de las expresiones lambda en Python 2: una expresión lambda crea un alcance variable, como lo defharía la declaración, pero dentro de lambda no se permiten declaraciones. La asignación como una declaración en Python significa que no se permiten asignaciones variables en lambda, pero una comprensión de la lista es una expresión ...
Este comportamiento se ha corregido en Python 3: no hay expresiones de comprensión ni generadores de variables de fuga.
Lo global realmente significa el alcance del módulo; el módulo principal de python es el __main__; todos los módulos importados son accesibles a través de la sys.modulesvariable; para obtener acceso a __main__uno puede usar sys.modules['__main__'], o import __main__; es perfectamente aceptable acceder y asignar atributos allí; se mostrarán como variables en el alcance global del módulo principal.
Si alguna vez se asigna un nombre en el alcance actual (excepto en el alcance de la clase), se considerará que pertenece a ese alcance, de lo contrario se considerará que pertenece a cualquier alcance adjunto que se asigne a la variable (puede que no se asigne todavía, o no), o finalmente el alcance global. Si la variable se considera local, pero aún no se ha establecido o se ha eliminado, la lectura del valor de la variable dará como resultado UnboundLocalErroruna subclase de NameError.
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
El alcance puede declarar que quiere explícitamente modificar la variable global (alcance del módulo), con la palabra clave global:
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
Esto también es posible incluso si se sombreó en el alcance adjunto:
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
En python 2 no hay una manera fácil de modificar el valor en el alcance adjunto; generalmente esto se simula teniendo un valor mutable, como una lista con una longitud de 1:
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
Sin embargo, en Python 3, nonlocalviene a rescatar:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
La nonlocaldocumentación dice que
Los nombres que figuran en una declaración no local, a diferencia de los que figuran en una declaración global, deben referirse a enlaces preexistentes en un ámbito adjunto (el alcance en el que se debe crear un nuevo enlace no puede determinarse sin ambigüedades).
es decir, nonlocalsiempre se refiere al ámbito externo no global más interno donde se ha vinculado el nombre (es decir, asignado, incluido el utilizado como la forvariable de destino, en la withcláusula o como un parámetro de función).
Cualquier variable que no se considere local al alcance actual, o cualquier alcance que la incluya, es una variable global. Se busca un nombre global en el diccionario global del módulo; si no se encuentra, el global se busca desde el módulo integrado; el nombre del módulo fue cambiado de python 2 a python 3; en python 2 era __builtin__y en python 3 ahora se llama builtins. Si asigna a un atributo del módulo integrado, será visible a partir de entonces para cualquier módulo como una variable global legible, a menos que ese módulo los sombree con su propia variable global con el mismo nombre.
Leer el módulo integrado también puede ser útil; suponga que desea la función de impresión de estilo python 3 en algunas partes del archivo, pero otras partes del archivo aún usan la printdeclaración. En Python 2.6-2.7 puede obtener la printfunción Python 3 con:
import __builtin__
print3 = __builtin__.__dict__['print']
En from __future__ import print_functionrealidad, no importa la printfunción en ningún lugar de Python 2; en cambio, solo deshabilita las reglas de análisis para la printdeclaración en el módulo actual, se maneja printcomo cualquier otro identificador de variable y, por lo tanto, permite que printla función se busque en las funciones incorporadas.