【问题标题】:Python: Generators and decorators with for a dictionaryPython:用于字典的生成器和装饰器
【发布时间】:2013-03-21 02:04:48
【问题描述】:

我创建了一个问题来锻炼一个人在 Python 中使用生成器、装饰器和字典的能力。

但是,我自己无法解决这个练习,并且想知道是否有可能解决。

是否可以使用包装生成器的装饰器函数以字典的形式缓存函数输出?

练习是:

编写一个装饰器来缓存函数调用结果。 将对 arg:result 存储在函数属性中的字典中 目的。使用生成器函数生成这些结果 在斐波那契函数上测试您的代码。

我尝试如下实现:

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'

有人知道此类问题的替代解决方案吗?

【问题讨论】:

    标签: python dictionary generator python-decorators


    【解决方案1】:

    您的具体错误

    错误在这里:

    return {func.__name__ + '(' + str(list(args))[1:-1] + ')' : str(result)}
    

    我相信,当您想返回结果时,您正在返回字典。我不太清楚你在缓存函数中实际在哪里进行缓存。

    一般评论

    这种缓存模式通常也称为记忆化。

    试试这个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))
    

    完整代码

    在您的示例中,Memoization 仍然适用于生成器,请注意打印语句向您显示正在获取 memoized 的结果。

    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
    

    【讨论】:

    • 谢谢,这几乎就是我想要的。但是如果我也想使用生成器呢?
    • 我不确定问题出在哪里,尝试运行上面的代码,看看 allfib(我相信它是你的生成器)仍然可以工作并且可以获取记忆值。
    猜你喜欢
    • 1970-01-01
    • 2019-03-26
    • 2019-07-09
    • 2019-05-10
    • 2014-01-01
    • 2014-12-26
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    相关资源
    最近更新 更多