Как применить запоминающий декоратор к методу экземпляра? - PullRequest
0 голосов
/ 02 июля 2018

Я бы хотел использовать декоратор для запоминания в методе класса. cExample.pri() звонит self.text(), но memorize, похоже, не знает о self. Когда memorize вызывает self.func(*key), отсутствует объект cExample, поэтому он жалуется на отсутствие аргументов.

Как изменить этот запоминающий декоратор, чтобы он мог передавать 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 голосов
/ 02 июля 2018

Вам нужно передать 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 будет передан wrapper в качестве позиционного аргумента и проксирован до cExample.pri.

...