有关类方法装饰器的一些问题

5 投票
4 回答
2233 浏览
提问于 2025-04-17 18:02

我有一段代码,想在一个 classmethod 上使用一个装饰器,代码如下:

import functools

def mydeco(function):
    @classmethod
    def wrapper(cls):
        return function(cls) 
    return functools.update_wrapper(wrapper, function)
    # return wrapper

class BaseClass(object):
    @classmethod
    @mydeco
    def foo(cls):
        return "42" 

print BaseClass.foo()

当我把 @mydeco 这一行注释掉时,代码就能正常运行,也就是说,文本 42 会被打印出来。但是一旦加上这个装饰器,我就遇到了几个问题:

  • 当我使用简单的 return wrapper 这一行时,我收到了一个错误提示:

    TypeError: 'classmethod' object is not callable
    

我想知道怎么才能正确地做到这一点,也就是说,在这个例子中,原始的函数能够不被改变地返回。

  • 当我使用更复杂的调用 return functools.update_wrapper(wrapper, function) 来保留一些原始函数的属性时,我又收到了一个错误提示:

    AttributeError: 'classmethod' object has no attribute '__module__'
    

我不确定这个错误是否和第一个问题有关,但我觉得它看起来是个不同的问题。欢迎任何具体的建议来解决这些问题。

上面的例子其实并没有真正“做”什么,它只是一个最简单的例子,用来展示我遇到的问题。

4 个回答

-2

可能问题出在 @classmethod 这个标记上,因为 def wrapper... 是一个函数的定义,而不是一个类的定义。

1

刚看到一篇关于装饰器的有趣文章,里面有个解释,但没有提供解决办法。

当装饰器用在 @classmethod 或 @staticmethod 上时,可能会出现异常。这是因为这些装饰器创建的包装器没有复制一些属性。

我自己也不知道怎么正确地装饰静态方法或类方法,但当我遇到类似的异常时,我会做以下其中一件事来让我的代码能正常工作,而不去深究原因:

  • 改变 @mydeco 和 @staticmethod 的顺序
  • 直接去掉 @staticmethod

更新

这里还有一篇关于如何正确实现描述符的很棒的文章

2

你有没有什么原因觉得这个方法不适合你呢?

import functools

def mydeco(function):
    def wrapper(*args, **kwargs):
        return function(*args, **kwargs) 
    return functools.update_wrapper(wrapper, function)

class BaseClass(object):
    @classmethod
    @mydeco
    def foo(cls):
        return "42" 

print BaseClass.foo()
42

撰写回答