python - simbolicas - scipy
¿Cómo definir la variable libre en python? (4)
Las definiciones de variables locales / globales / libres de Python doc :
Si un nombre está enlazado en un bloque, es una variable local de ese bloque, a menos que se declare como no local. Si un nombre está vinculado al nivel del módulo, es una variable global . (Las variables del bloque de código del módulo son locales y globales.) Si una variable se usa en un bloque de código pero no está definida allí, es una variable libre .
Código 1:
>>> x = 0
>>> def foo():
... print(x)
... print(locals())
...
>>> foo()
0
{}
Código 2:
>>> def bar():
... x = 1
... def foo():
... print(x)
... print(locals())
... foo()
...
>>> bar()
1
{''x'':1}
Las variables libres son devueltas por locals()
cuando se llama en bloques de función, pero no en bloques de clase.
En el Code 1
, x
es una variable global , y se usa pero no se define en foo()
.
Sin embargo, no es una variable libre , porque no es devuelta por locals()
.
Creo que no es lo que dijo el doc. ¿Existe una definición técnica para la variable libre ?
Definición de una variable libre: utilizada, pero no global ni unida .
Por ejemplo:
-
x
no es libre en el Código 1, porque es una variable global . -
x
no está libre en labar()
en el Código 2, porque es una variable enlazada . -
x
es gratis enfoo()
.
Python hace esta distinción debido a los cierres. Una variable libre no se define en el entorno actual, es decir, la recopilación de variables locales, ¡y tampoco es una variable global! Por lo tanto, debe definirse en otra parte. Y este es el concepto de los cierres. En el Código 2, foo()
cierra en x
definida en la bar()
. Python utiliza el alcance léxico. Esto significa que el intérprete puede determinar el alcance con solo mirar el código.
Por ejemplo: x
se conoce como una variable en foo()
, porque foo()
está encerrada por la bar()
, y x
está vinculada en la bar()
.
El alcance global es tratado especialmente por Python. Sería posible ver el alcance global como un alcance más externo, pero esto no se hace debido al rendimiento (creo). Por lo tanto, no es posible que x
sea libre y global .
Exención
La vida no es tan simple. Existen variables globales libres . Python docs (modelo de ejecución) dice:
La declaración global tiene el mismo alcance que una operación de enlace de nombre en el mismo bloque. Si el ámbito de cierre más cercano para una variable libre contiene una declaración global, la variable libre se trata como global.
>>> x = 42
>>> def foo():
... global x
... def baz():
... print(x)
... print(locals())
... baz()
...
>>> foo()
42
{}
Yo no lo sabía yo mismo. Todos estamos aquí para aprender.
Las variables no son más que ubicaciones de memoria reservadas para almacenar valores. Esto significa que al crear una variable, se reserva algo de espacio en la memoria.
Según el tipo de datos de una variable, el intérprete asigna memoria y decide qué se puede almacenar en la memoria reservada. Por lo tanto, al asignar diferentes tipos de datos a las variables, puede almacenar números enteros, decimales o caracteres en estas variables.
Asignación de valores a variables
Las variables de Python no necesitan una declaración explícita para reservar espacio de memoria. La declaración ocurre automáticamente cuando asignas un valor a una variable. El signo igual (=) se utiliza para asignar valores a las variables.
No hay una palabra clave explícita para declarar una variable libre en Python. Basado en la definición de una función y las declaraciones dentro y alrededor de ella, Python clasificará las variables en variables enlazadas, de celda y libres.
El siguiente ejemplo ilustra este concepto utilizando el objeto de código de la función que encapsula las variables mencionadas en el párrafo anterior.
def func(arg1, arg2=2):
def inner_func(arg3=arg2):
return arg1, arg3
arg1, arg2 = None
return inner_func
Para '' func '':
• arg1 y arg2 son variables ligadas
• arg1 es una variable de celda ya que es una variable libre dentro de '' inner_func ''
• No hay variables libres.
func.__code__.co_varnames
(''arg1'', ''arg2'', ''inner_func'')
func.__code__.co_cellvars
(''arg1'',)
func.__code__.co_freevars
()
Para '' inner_func '':
• arg3 es una variable enlazada
• arg1 es una variable libre
• No hay variables de celda
inner_func.__code__.co_varnames
(''arg3'',)
inner_func.__code__.co_freevars
(''arg1'')
inner_func.__code__.co_cellvars
()
Por lo que he entendido, la documentación es de hecho un poco ambigua en las variables libres. Existen variables globales libres que se tratan como variables globales y variables libres vinculadas de forma léxica . Eli Bendersky lo resume muy bien en una publicación de blog sobre tablas de símbolos :
Desafortunadamente, hay una taquigrafía en el núcleo de Python que inicialmente puede confundir a los lectores en cuanto a qué es exactamente una variable "libre". Afortunadamente, es una pequeña confusión que es fácil de poner en orden. La referencia del modelo de ejecución dice:
Si una variable se usa en un bloque de código pero no está definida allí, es una variable libre.
Esto es consistente con la definición formal . Sin embargo, en la fuente, "libre" en realidad se usa como una abreviatura para "variable libre ligada léxicamente" (es decir, variables para las que se ha encontrado una vinculación en un ámbito adjunto), con "global" para referirse a todos los restantes libres. variables Por lo tanto, al leer el código fuente de CPython, es importante recordar que el conjunto completo de variables libres incluye tanto las variables etiquetadas específicamente como "libres", como las etiquetadas como "globales".
Por lo tanto, para evitar una confusión, digo "ligado léxicamente" cuando quiero referirme a las variables realmente tratadas en CPython como libres.
(énfasis mío)
La razón por la que se usó esta abreviatura es probablemente porque cuando tienes una variable libre global realmente no hay ningún cambio en el código de byte emitido. Si una variable global
es ''libre'' o si no lo es, no cambia el hecho de que la búsqueda de ese nombre usará LOAD_GLOBAL
en ambos casos. Así que las variables libres globales no son tan especiales.
Por otro lado, las variables vinculadas léxicamente se tratan especialmente y se encierran en objetos de cell
, los objetos son el espacio de almacenamiento para las variables libres vinculadas léxicamente y se ubican en el atributo __closure__
para una función determinada. Se LOAD_DEREF
instrucción especial LOAD_DEREF
para estos que examina las celdas presentes para las variables libres. La descripción para la instrucción LOAD_DEREF
es:
LOAD_DEREF(i)
Carga la celda contenida en la ranura i de la celda y el almacenamiento variable libre
Por lo tanto, en Python, las variables libres solo hacen una diferencia como concepto en situaciones donde una definición para un objeto que tiene estado está anidada (es decir, estáticamente) en otra definición para un objeto que tiene estado.