I created a problem that exercises a one's ability to use generators, decorators, and dictionaries in Python.
However, I cannot solve this exercise myself, and was wondering if it is at all possible to solve.
Is it possible to cache function output in the form of a dictionary using a decorator function that wraps a generator?
The exercise is:
Write a decorator to cache function invocation results. Store pairs arg:result in a dictionary in an attribute of the function object. Generate these results using a generator function Test your code on the fibonacci function.
I have attempted to implement it as follows:
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
However, I get the following error:
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'
Does anybody know an alternative solution to a question like this?
The error is here:
return {func.__name__ + '(' + str(list(args))[1:-1] + ')' : str(result)}
You are returning a dictionary when you want to return result I believe. I don't quite see where you are doing any cacheing actually inside cache function.
This pattern of cacheing is also commonly called memoization.
Try this http://avinashv.net/2008/04/python-decorators-syntactic-sugar/ . Scroll down to the portion about fibonacci. The following code is found there:
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]
Then simply do:
@memoize
def fibonacci(n):
assert n >= 0
if n < 2:
return n
else:
return (fibonacci(n-1) + fibonacci(n-2))
Memoization still works on the generator in your example, note the print statements show you that memoized results are being fetched.
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.