Cierre de python con asignación de variable externa dentro de la función interna

Tengo este pedazo de código:

#!/usr/bin/env python def get_match(): cache=[] def match(v): if cache: return cache cache=[v] return cache return match m = get_match() m(1) 

Si lo ejecuto, dice:

 UnboundLocalError: local variable 'cache' referenced before assignment 

pero si hago esto:

 #!/usr/bin/env python def get(): y = 1 def m(v): return y + v return m a=get() a(1) 

corre.

¿Hay algo con la lista? o mi organizacion de codigo esta mal?

El problema es que la variable cache no está en el scope de la función de coincidencia. Esto no es un problema si solo quiere leerlo como en su segundo ejemplo, pero si se lo asigna, Python lo interpreta como una variable local. Si está usando python 3, puede usar la palabra clave nonlocal para resolver este problema: para python 2, desafortunadamente no existe una solución alternativa.

 def f(): v = 0 def x(): return v #works because v is read from the outer scope def y(): if v == 0: #fails because the variable v is assigned to below v = 1 #for python3: def z(): nonlocal v #tell python to search for v in the surrounding scope(s) if v == 0: v = 1 #works because you declared the variable as nonlocal 

El problema es algo similar con las variables globales: es necesario usar global cada vez que se asigna a una variable global, pero no para leerla.

Una breve explicación de las razones detrás de eso: El intérprete de Python comstack todas las funciones en un objeto especial de tipo function . Durante esta comstackción, verifica todas las variables locales que crea la función (para la recolección de basura, etc.). Estos nombres de variables se guardan dentro del objeto de función. Como es perfectamente legal “sombrear” una variable de ámbito externo (crear una variable con el mismo nombre), se asume que cualquier variable que se asigna y que no se declara explícitamente como global (o nonlocal en python3) es una variable local .

Cuando se ejecuta la función, el intérprete tiene que buscar cada referencia de variable que encuentra. Si se encontró que la variable era local durante la comstackción, se busca en el diccionario de funciones f_locals. Si aún no se ha asignado, esto genera la excepción que encontró. Si la variable no está asignada en el scope de las funciones y, por lo tanto, no forma parte de sus locales, se busca en los ámbitos circundantes: si no se encuentra allí, esto genera una excepción similar.

Acceder a una variable es diferente de asignarla.

Tienes una situación similar con variables globales. Puede acceder a ellos en cualquier función, pero si intenta asignárselos sin la statement global , se volverá a declarar en el contexto local.

Desafortunadamente para las funciones locales, no hay un equivalente de la statement global , pero puede omitir la restatement reemplazando

 cache=[v] 

con:

 cache[:] = [v] 

Como Python ve cache=[v] – asignación a cache , la trata como una variable local. Por lo tanto, el error es bastante razonable: no se definió una cache variable local antes de su uso en la sentencia if .

Probablemente quieras escribirlo como:

 def get_match(): cache=[] def match(v): if cache: return cache cache.append(v) return cache return match m = get_match() m(1) 

Lecturas altamente recomendadas: Modelo de ejecución: nomenclatura y vinculación y PEP 227: ámbitos estáticamente nesteds

Reemplazar

 cache=[] def match(v): 

con

 def match(v,cache=[]) 

Explicación: su código declara que la cache es una variable de get_match , sobre la cual la match(v) devuelta no sabe nada (debido a la siguiente asignación). Sin embargo, usted quiere que el cache sea ​​parte del espacio de nombres de la match .

Sé que de esta manera un usuario “malévolo” podría redefinir el caché, pero ese es su propio error. Si esto fuera un problema, la alternativa es:

 def match(v): try: if cache: return cache except NameError: cache = [] ... 

(Ver aquí )