2015-02-24 3 views
0

Я использую рецепт memoize от here и немного изменил его для функции, которая возвращает 2 значения. Я использую эту оболочку для создания двух отдельных функций, которые возвращают первое и второе значения по отдельности, но оценки функций кэшируются, так что нет никаких накладных расходов при вызове любой из возвращаемых функций с тем же аргументом. Вот код для этой обертки.Memoize wrapper для функций класса-члена для возврата частичных значений

def memoize(obj, cache_limit=10): 
    ''' 
    This function caches the return value each time it is called. partial() is used to return the appropriate value. 
    Cache size is limited to 10 
    See here for details on this design pattern: https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize 
    ''' 
    cache = obj.cache = {} 
    key_cache = collections.deque() 

    @functools.wraps(obj) 
    def memoizer(which, *args, **kwargs): 
     key = str(args) 
     if key not in cache: 
      cache[key] = obj(*args, **kwargs) 
      key_cache.append(key) 
      if len(key_cache) >= cache_limit: 
       del cache[key_cache.popleft()] 
     return cache[key][which] 
    return functools.partial(memoizer, 0), functools.partial(memoizer, 1) 

Теперь я пытаюсь использовать это на функцию f, которая определена в классе таким образом:

class test_function: 
    def __init__(self): 
     '''''' 

    def f(self,x): 
     return 2*x, 3*x 

И я называю это таким образом

a = test_function() 
f_v1, f_v2 = memoize(a.f) 

В случае успеха f_v1(x) вернется 2x и f_v2(x) вернется 3x. Но это не с ошибкой:

AttributeError: 'instancemethod' object has no attribute 'cache' 

Мой код отлично работает, если функция объявлена ​​вне класса. Что мне не хватает? Я использую Python 2.7.

ответ

1

Методы - это другой вид объекта, чем функции (объект instancemethod, как следует из сообщения об ошибке, этот тип доступен как types.MethodType). В отличие от объектов-объектов, методы экземпляра не имеют __dict__, поэтому вы не можете устанавливать на них произвольные атрибуты; вы не можете сделать obj.someMethod.someAttribute = "blah", чтобы создать свой собственный настраиваемый атрибут someAttribute по методу.

Непонятно, почему вы храните кеш на объекте в любом случае, так как вы никогда на самом деле не обращаетесь к нему оттуда. Если вы просто использовать локальную переменную cache, он будет сохранен в затворе и будет работать нормально:

def memoize(obj, cache_limit=10): 
    ''' 
    This function caches the return value each time it is called. partial() is used to return the appropriate value. 
    Cache size is limited to 10 
    See here for details on this design pattern: https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize 
    ''' 
    cache = {} 
    key_cache = collections.deque() 

    @functools.wraps(obj) 
    def memoizer(which, *args, **kwargs): 
     key = str(args) 
     if key not in cache: 
      cache[key] = obj(*args, **kwargs) 
      key_cache.append(key) 
      if len(key_cache) >= cache_limit: 
       del cache[key_cache.popleft()] 
     return cache[key][which] 
    return functools.partial(memoizer, 0), functools.partial(memoizer, 1) 

>>> a = test_function() 
... f_v1, f_v2 = memoize(a.f) 
>>> f_v1(2) 
4 
>>> f_v2(2) 
6 
+0

Я вижу ... Скажем у меня есть функция 'f2()', что я хочу memoize с этой оберткой будет ли 'cache' не конфликтовать с' cache' с 'f()'? Я проверил это, и он работает нормально, но можете ли вы объяснить объем «кеша»? – sriramn

+0

@RazorXsr: Поскольку 'cache' является локальной переменной, новый создается каждый раз, когда вы вызываете' memoize'. На этом сайте есть множество вопросов о закрытии (например, [этот] (http://stackoverflow.com/questions/4020419/why-arent-python-nested-functions-called-closures)). Google для «закрытия Python», чтобы найти много информации о закрытии Python. – BrenBarn

Смежные вопросы