Memoization装饰器

时间:2017-03-03 15:51:23

标签: python

我有以下伪代码:

class myClass()
  def slow_method(self):
     try:
         return self.memo_slow_method
     except:
         self.memo_slow_method = some_slow_function()
         return self.memo_slow_method

是否可以构建一个执行完全此逻辑的memoization装饰器?

限制:

  • 虽然memo_slow_method不需要直接访问,但必须在对象上定义,以便在对象本身被清除时清除它 - 非常重要
  • 无需考虑self以外的参数 - 不会传递任何参数。

PS我一直在使用@lrucache,但它不适合我的目的。它确实需要完全遵循上述逻辑。

2 个答案:

答案 0 :(得分:2)

您可以使用描述符(类似属性)代替装饰器:

class Memoize(object):
    def __init__(self, name, func):
        self.name = name  # name of the memo attribute
        self.func = func  # the function that is executed when there is no memo

    def __get__(self, obj, typ=None):
        if obj:
            try:
                return getattr(obj, self.name)
            except:
                setattr(obj, self.name, self.func())
                return getattr(obj, self.name)
        else:
            return self

然后设置描述符:

class Fun(object):
    meth = Memoize('x', lambda: print('in') or 10)

然后是互动测试:

>>> f = Fun()
>>> f.meth  # function is executed
'in'
10
>>> f.x
10
>>> f.meth  # function is not executed
10

如果你真的想要一个装饰者:

def memoize(func):
    def inner(self):
        try:
            return self.memo_slow_method   # hardcoded memo attribute name
        except:
            self.memo_slow_method = func(self)  # execute the method body
            return self.memo_slow_method
    return inner

class Fun(object):
    @memoize
    def meth(self):
        print('in')
        return 100

>>> f = Fun()
>>> f.meth()
'in'
100
>>> f.meth()
100
>>> f.memo_slow_method
100

答案 1 :(得分:0)

这是一个装饰器,可以按照要求完全实现您的逻辑。 它通过为其添加前缀,从函数名称(可在func.__name__中获得)中为备注字段的名称加密:

from __future__ import print_function
import time
from functools import wraps

memo_prefix = '_memo_' # Check for possible name collision

def deco(func):
    memo_field_name = memo_prefix + func.__name__

    def ret_func(self):
        try:
            return getattr(self, memo_field_name)
        except AttributeError:
            ret_val = func(self)
            setattr(self, memo_field_name, ret_val)
            return ret_val
    return ret_func

def some_slow_function():
    for x in range(3):
        time.sleep(1)
        print('Waiting...', x)
    return 'Done'

class myClass():
    @deco
    def slow_method(self):
        return some_slow_function()

现在测试一下:

In [2]: it = myClass()

In [3]: print(it.slow_method())
Waiting... 0
Waiting... 1
Waiting... 2
Done

In [4]: print(it.slow_method())
Done

In [5]: print(it.__dict__)
{'_memo_slow_method': 'Done'}