que he estado tratando de aprender Python, y aunque estoy entusiasmado con el uso de cierres en Python, he estado teniendo problemas para conseguir algo de código para que funcione correctamente:Cierres en Python
def memoize(fn):
def get(key):
return (False,)
def vset(key, value):
global get
oldget = get
def newget(ky):
if key==ky: return (True, value)
return oldget(ky)
get = newget
def mfun(*args):
cache = get(args)
if (cache[0]): return cache[1]
val = apply(fn, args)
vset(args, val)
return val
return mfun
def fib(x):
if x<2: return x
return fib(x-1)+fib(x-2)
def fibm(x):
if x<2: return x
return fibm(x-1)+fibm(x-2)
fibm = memoize(fibm)
Básicamente, lo se supone que esto es hacer cierres para mantener el estado memorizado de la función. Me doy cuenta de que probablemente haya muchas formas más rápidas, fáciles de leer y, en general, más "pitónicas" para implementar esto; sin embargo, mi objetivo es comprender exactamente cómo funcionan los cierres en Python, y cómo se diferencian de Lisp, por lo que no estoy interesado en soluciones alternativas, simplemente por qué mi código no funciona y qué puedo hacer (si es que hay algo) para corregirlo. eso.
El problema que estoy corriendo en es cuando trato de usar fibm
- Python insiste en que no está definido get
:
Python 2.6.1 (r261:67515, Feb 1 2009, 11:39:55)
[GCC 4.0.1 (Apple Inc. build 5488)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import memoize
>>> memoize.fibm(35)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "memoize.py", line 14, in mfun
cache = get(args)
NameError: global name 'get' is not defined
>>>
En vista de que soy nuevo en Python, no sé si He hecho algo mal, o si esto es solo una limitación del lenguaje. Espero que sea el primero. :-)
Entonces, es un defecto en el lenguaje. Esperaba que no fuera a decir eso. :-(Una posible solución es almacenar el valor en una estructura mutable (como una lista) y modificar eso, pero es bastante hackish. Quería una versión 2.X para compatibilidad, pero podría tener que dar el salto a 3000. –
Hay una solución, bastante simple, a menos que se confunda con tu concepto de pureza: simplemente haz que get() sea una función global. Dicho esto, debo decir que tu método de memorización me parece demasiado complicado :) – sykora
¿Cómo funciona correctamente? Solo elimina las líneas "global get" y "oldget = get" y nunca usa un valor guardado. –