5

我一直在测试这种缓存方法/代码: http ://code.activestate.com/recipes/498245-lru-and-lfu-cache-decorators/?c=15348

在某些情况下,我得到这个(或类似的)错误:“AttributeError:'str'对象没有属性'模块'”

这里是代码示例,这些工作正常:

if __name__ == '__main__':
@lru_cacheItem(maxsize=20)
def f(x, y):
    return 3*x+y

domain = range(5)
from random import choice
for i in range(1000):
    r = f(choice(domain), choice(domain))

print('Hits:{0}'.format(f.hits), 'Misses:{0}'.format(f.misses))

@lfu_cacheItem(maxsize=20)
def f(x, y):
    return 3*x+y

domain = range(5)
from random import choice
for i in range(1000):
    r = f(choice(domain), choice(domain))

print('Hits:{0}'.format(f.hits), 'Misses:{0}'.format(f.misses))  


@lru_cacheItem(maxsize=20)
def myString(a, b):
    return '{0} and {1}'.format(a, b)

a = 'crap'
b = 'shit'
for i in range(1000):
    r = myString(a, b)

print('Hits:{0}'.format(myString.hits), 'Misses:{0}'.format(myString.misses)) 

这不会:

if __name__ == '__main__':    
class P4client(object):
    def __init__(self):
        pass

    def checkFileStats(self, filePath):
        results = 'The filepath: {0}'.format(filePath)
        print results
        return results

p4client = P4client()

filePath = (r"C:\depot\tester.tga")

@lfu_cacheItem            
def p4checkFileStats(filePath):
    '''Will cache the fstats return'''
    p4checkResults = p4client.checkFileStats(filePath)
    return p4checkResults    

p4checkFileStats(filePath)

我不知道如何解决这个问题......这似乎是 functools 中的一个问题,我假设我在我正在包装的函数中调用一个类/方法以某种方式做到这一点?

4

1 回答 1

6
@lfu_cacheItem            
def p4checkFileStats(filePath):

您在这里缺少括号:

@lfu_cacheItem()            
def p4checkFileStats(filePath):

所有期望“选项”的装饰器,即您可以用作:

@decorator(a=Something, b=Other, ...)
def the_function(...):

装饰时必须始终调用,即使您不提供参数:

@decorator()
def the_function(...):

你为什么想知道?好吧,首先要记住装饰器是接受函数作为参数的普通函数:

In [1]: def hooray(func):
   ...:     print("I'm decorating function: {.__name__}".format(func))
   ...:     return func

In [2]: @hooray
   ...: def my_function(): pass
I'm decorating function: my_function

如您所见hooray,被称为. 事实上,这是使用装饰器时真正发生的情况:

In [3]: def my_function(): pass
   ...: my_function = hooray(my_function)
   ...: 
I'm decorating function: my_function

现在,如果您想将选项传递给装饰器,您可以创建一个返回装饰器的函数。这正是lfu_cache您链接的食谱中发生的情况:

def lfu_cache(maxsize=100):
    # ...
    def decorating_function(user_function):
        # ...
    return decorating_function

现在在这里您可以看到这lfu_cache确实是一个功能。这个函数创建一个装饰器,调用decorating_function并返回它。这意味着在调用时:

@lfu_cache(maxsize=20)
def my_function(): pass

这就是发生的事情:

def my_function(): pass
decorator = lfu_cache(maxsize=20)
my_function = decorator(my_function)

如您所见, firstlfu_cache被调用,并返回一个装饰器。然后调用装饰器来装饰函数。如果忘记括号会怎样?这是做什么的:

@lfu_cache
def my_function(): pass

做?

很简单,它lfu_cache用作一个简单的装饰器:

def my_function(): pass
my_function = lfu_cache(my_function)

但这很糟糕!您传递了一个函数作为maxsize参数,返回的值lfu_cachedecorating_function之前的!

要了解有关装饰器的更多信息,请阅读答案。

于 2013-08-28T16:58:21.097 回答