Python:为字典使用生成器和装饰器
我设计了一个问题,目的是考验大家在Python中使用生成器、装饰器和字典的能力。
不过,我自己没法解决这个练习,想知道这是否真的能解决。
能不能用一个装饰器函数来缓存函数的输出,并把结果以字典的形式存储起来,这个装饰器还要包裹一个生成器?
这个练习是:
写一个装饰器,用来缓存函数调用的结果。把参数和结果的对应关系存储在函数对象的一个属性中的字典里。用生成器函数来生成这些结果。然后在斐波那契函数上测试你的代码。
我尝试这样实现:
def cachefunc(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return {func.__name__ + '(' + str(list(args))[1:-1] + ')' : str(result)}
wrapper.__name__ = func.__name__
wrapper.__doc__ = func.__doc__
return wrapper
@cachefunc
def fibonacci(n):
assert n >= 0
if n < 2:
return n
else:
return (fibonacci(n-1) + fibonacci(n-2))
def allfib():
n = 0
while True:
yield fibonacci(n)
n += 1
result = []
generator = allfib()
while len(result) < 10:
x = next(generator)
result.append(x)
print result
但是,我遇到了以下错误:
python dg.py
Traceback (most recent call last):
File "dg.py", line 32, in <module>
x = next(generator)
File "dg.py", line 26, in allfib
yield fibonacci(n)
File "dg.py", line 10, in wrapper
result = func(*args, **kwargs)
File "dg.py", line 22, in fibonacci
return (fibonacci(n-1) + fibonacci(n-2))
TypeError: unsupported operand type(s) for +: 'dict' and 'dict'
有没有人知道类似问题的其他解决方案?
1 个回答
1
你的具体错误
错误出现在这里:
return {func.__name__ + '(' + str(list(args))[1:-1] + ')' : str(result)}
你返回的是一个字典,但我觉得你想返回的是结果。我不太明白你在缓存函数里面到底做了什么缓存。
一般评论
这种缓存的方式通常被称为记忆化(memoization)。
你可以试试这个链接 http://avinashv.net/2008/04/python-decorators-syntactic-sugar/。往下滚动到关于斐波那契数列的部分。那里有以下代码:
class memoize:
def __init__(self, function):
self.function = function
self.func_name = function.__name__
self.memoized = {}
def __call__(self, *args):
try:
print "Using Memo Solution for " + self.func_name + " on " + str(args)
return self.memoized[args]
except KeyError:
print "Computing Solution Now for " + self.func_name + " on " + str(args)
self.memoized[args] = self.function(*args)
return self.memoized[args]
然后你只需这样做:
@memoize
def fibonacci(n):
assert n >= 0
if n < 2:
return n
else:
return (fibonacci(n-1) + fibonacci(n-2))
完整代码
在你的例子中,记忆化仍然适用于生成器,注意打印语句显示你正在获取记忆化的结果。
class memoize:
def __init__(self, function):
self.function = function
self.func_name = function.__name__
self.memoized = {}
def __call__(self, *args):
try:
print "Using Memo Solution for " + self.func_name + " on " + str(args)
return self.memoized[args]
except KeyError:
print "Computing Solution Now for " + self.func_name + " on " + str(args)
self.memoized[args] = self.function(*args)
return self.memoized[args]
@memoize
def fibonacci(n):
assert n >= 0
if n < 2:
return n
else:
return (fibonacci(n-1) + fibonacci(n-2))
def allfib():
n = 0
while True:
yield fibonacci(n)
n += 1
result = []
generator = allfib()
while len(result) < 10:
x = next(generator)
result.append(x)
print result