decorators - Ámbito de variables en el decorador python.
python decorator class (2)
Actualmente no hay manera de hacer lo mismo para las variables en los ámbitos de funciones de cierre, pero Python 3 introduce una nueva palabra clave, "no local", que actuará de forma similar a la global, pero para los ámbitos de función anidados.
así que en tu caso solo usa como:
def inner(*args, **kwargs): nonlocal nr_of_rounds lst = [] while nr_of_rounds > 0: lst.append(func(*args, **kwargs)) nr_of_rounds -= 1 return max(lst) return inner
Para más información, ¿ breve descripción de las reglas de alcance?
Tengo un problema muy raro en un decorador de Python 3.
Si hago esto:
def rounds(nr_of_rounds):
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
return nr_of_rounds
return inner
return wrapper
funciona bien Sin embargo, si hago esto:
def rounds(nr_of_rounds):
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
lst = []
while nr_of_rounds > 0:
lst.append(func(*args, **kwargs))
nr_of_rounds -= 1
return max(lst)
return inner
return wrapper
Yo obtengo:
while nr_of_rounds > 0:
UnboundLocalError: local variable ''nr_of_rounds'' referenced before assignment
En otras palabras, puedo usar nr_of_rounds
en la función interna si lo uso en una devolución, pero no puedo hacer nada más con ella. ¿Porqué es eso?
Ya que nr_of_rounds
es captado por el cierre , puedes considerarlo como una variable de "solo lectura". Si desea escribir en él (por ejemplo, para disminuirlo), debe indicarle explícitamente a python: en este caso, la palabra clave nonlocal python3.x funcionará.
Como una breve explicación, lo que hace Cpython cuando encuentra una definición de función es mirar el código y decidir si todas las variables son locales o no locales . Las variables locales (por defecto) son cualquier cosa que aparece en el lado izquierdo de una declaración de asignación, las variables de bucle y los argumentos de entrada. Cualquier otro nombre no es local. Esto permite algunas optimizaciones limpias 1 . Para utilizar una variable no local de la misma forma que lo haría con una local, debe indicarle explícitamente a Python mediante una declaración global
o nonlocal
. Cuando Python encuentra algo que cree que debería ser un local, pero en realidad no lo es, obtienes un UnboundLocalError
.
1 El generador de bytecode de Cpython convierte los nombres locales en índices en una matriz, de modo que la búsqueda de nombres locales (la instrucción de bytecode LOAD_FAST) es tan rápida como la indexación de una matriz más la sobrecarga de bytecode normal.