Глобальный кеш с определенными атрибутами объекта в качестве входа в Python - PullRequest
0 голосов
/ 30 октября 2018

Пытаясь создать декоратор кеша на уровне класса, я наткнулся на библиотеку ring, которая может сохранять входные и выходные данные функции в глобальном масштабе. Это в основном позволяет мне добиться следующего поведения, учитывая class определение Calculate, как показано ниже:

import ring

class Calculate:

    @ring.dict({})
    def sum(self, a, b):
       print('actually calculating')
       sum = a + b
       return sum

это поведение, которое я пытаюсь достичь с помощью Calculate

>>> calculate = Calculate()
>>> calcualte.sum(5,7)
actually calculating
12

>>> different_calculate = Calculate()
>>> different_calculate.sum(5,7)
12    #this outputs 12 straight from the cache from first calculate. 
#Note that even if 'different_calculate' and 'calculate' are different instantiations of 'Calculate', the cache works at a class level. Therefore the sum is not actually REcalculated.

Теперь мне нужно добиться того же поведения с sum, на этот раз это свойство. Проблема, с которой я здесь сталкиваюсь, заключается в том, что @property def принимает в качестве аргумента self. Поэтому при попытке кеширования, как в предыдущем примере, он не будет работать, потому что входные данные больше не num1 и num2, а self, которые меняются при каждом создании. Поэтому он никогда не извлечет из кэша инстанции другого класса, так как self всегда меняется с каждой инстанцией. Смотри ниже:

import ring

class Calculate:
   def __init__(self, num1, num2):
      self.num1 = num1
      self.num2 = num2

    @ring.dict({})
    @property
    def sum(self):
       print('actually calculating')
       sum = num1 + num2
       return sum

>>> calculate = Calculate()
>>> calcualte.sum(5,7)
actually calculating
12

>>> different_calculate = Calculate()
>>> different_calculate.sum(5,7)
actually calculating
12

Чтобы решить эту проблему, я должен как-то сказать библиотеке кеша не смотреть на self как на вход, а на self.num1, self.num2. Код должен быть примерно таким:

   @ring.dict(self.num1, self.num2)  # <--- this does not exist
    @property
    def sum(self):
       print('actually calculating')
       sum = num1 + num2
       return sum

Есть ли способ, которым я могу сделать это с ring или любой другой библиотекой кеша Python?

1 Ответ

0 голосов
/ 30 октября 2018

Итак, после получения вдохновения от здесь , я в итоге просто создал свою собственную функцию запоминания, вот так:

memo = {}

def memoize(*attrs):  
    def wrapper(f):  
        def helper(obj):
            key = tuple([getattr(obj,attr) for attr in attrs])
            if key not in memo:            
                memo[key] = f(obj)
            return memo[key]
        return helper
    return wrapper




class Calculate:
    def __init__(self, num1, num2):
        self.num1 = num1
        self.num2 = num2

    @property
    @memoize('num1', 'num2')  
    def sum(self):
        print('actually calculating')
        sum = self.num1 + self.num2
        return sum


>>> calculate = Calculate(6,9)
>>> calculate.sum
actually calculating
15

>>> another_calculate = Calculate(6,9)
>>> another_calculate.sum
15
...