【问题标题】:AttributeError: 'str' object has no attribute '__module__'AttributeError:“str”对象没有属性“__module__”
【发布时间】:2013-08-29 01:12:44
【问题描述】:

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

在某些情况下,我会收到此(或类似的)错误: "AttributeError: 'str' 对象没有属性 'module'"

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

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 中的一个问题,我假设我在包装的函数中调用了一个类/方法?

【问题讨论】:

    标签: python caching


    【解决方案1】:
    @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)
    

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

    @lfu_cache
    def my_function(): pass
    

    做吗?

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

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

    但这很糟糕!您将函数作为maxsize 参数传递,lfu_cache 返回的值是之前的decorating_function

    要了解有关装饰器的更多信息,请阅读 this 所以回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-10
      • 2021-10-04
      • 2019-12-02
      • 2021-09-25
      • 2014-03-04
      相关资源
      最近更新 更多