如何将一个记忆装饰器应用于实例方法?

时间:2018-07-02 14:15:18

标签: python python-3.x python-decorators

我想在类方法上使用一个记忆装饰器。 cExample.pri()呼叫self.text(),但memorize似乎不了解self。当memorize调用self.func(*key)时,它会丢失cExample obj,因此会抱怨缺少参数。

如何更改此记忆装饰器,使其能够将调用者的self传递给函数?

Python3.5.2

class memorize(dict):
    def __init__(self, func):
        self.func = func

    def __call__(self, *args):
        return self[args]

    def __missing__(self, key):
        result = self[key] = self.func(*key)
        return result

class cExample():
    @memorize
    def pri(self, text):
        return self.text(text)

    def text(self, text):
        return text

c = cExample()
print(c.pri('hi'))

输出:

Traceback (most recent call last):
  File "x.py", line 23, in <module>
    print(c.pri('hi'))
  File "x.py", line 7, in __call__
    return self[args]
  File "x.py", line 11, in __missing__
    result = self[key] = self.func(*key)
TypeError: pri() missing 1 required positional argument: 'text'

1 个答案:

答案 0 :(得分:1)

您需要将self(即c)传递给cExample.pri(即self.func)。但是__missing__不允许您这样做:它只接收密钥。

您可以使用基于函数的装饰器将其重写:

import functools

def memorize2(f):
    cache = {}
    @functools.wraps(f)
    def wrapper(*args):
        if args not in cache:
            cache[args] = f(*args)
        return cache[args]
    return wrapper

class cExample():
    @memorize2
    def pri(self, text):
        return self.text(text)

    def text(self, text):
        return text

c = cExample()
print(c.pri('hi'))  # hi

(我正在使用functools.wraps来保留修饰方法的原始名称)。

在这种方法中,self将作为位置arg传递到wrapper,并被代理到cExample.pri