Próbowałam nauczyć się Pythona, a ja jestem entuzjastą za pomocą zamknięć w Pythonie, miewam problemy z uzyskaniem kodu do pracy prawidłowo:Zamknięcia w Pythonie
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)
Zasadniczo, co to ma zrobić, to użyć zamknięć, aby utrzymać zapamiętany stan funkcji. Zdaję sobie sprawę, że prawdopodobnie jest o wiele szybszy, łatwiejszy do odczytania i ogólnie bardziej "Pythoniczny" sposób na wdrożenie tego; jednak moim celem jest dokładne zrozumienie, w jaki sposób zamknięcia działają w języku Python i jak różnią się one od Lispa, więc nie interesują mnie alternatywne rozwiązania, tylko dlaczego mój kod nie działa i co mogę zrobić (jeśli w ogóle), aby naprawić to.
Problem używam do jest, gdy próbuję użyć fibm
- Python twierdzi, że get
nie jest zdefiniowana:
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
>>>
Widząc jak jestem nowy w Pythonie, ja nie wiem, czy Zrobiłem coś złego, lub jeśli jest to tylko ograniczenie tego języka. Mam nadzieję, że to ta pierwsza. :-)
Jest to wada w języku. Miałem nadzieję, że tego nie powiesz. :-(Możliwym obejściem jest przechowywanie wartości w zmiennej strukturze (takiej jak lista) i modyfikowanie tego, ale to jest dość hackowskie. Potrzebowałem wersji 2.X do kompatybilności, ale być może będę musiał zrobić skok do 3000. –
Istnieje obejście tego problemu, dość proste, o ile nie zakłóci to twojej koncepcji czystości - po prostu spraw, aby get() stał się funkcją globalną To powiedziawszy, muszę powiedzieć, że twoja metoda zapamiętywania wydaje mi się zbyt skomplikowana. :) – sykora
Jak to działa poprawnie? Usuwa tylko linie "global get" i "oldget = get" i nigdy nie używa zapisanej wartości. –