【问题标题】:Why can @decorator not decorate a staticmethod or a classmethod?为什么@decorator 不能装饰静态方法或类方法?
【发布时间】:2010-12-31 13:39:55
【问题描述】:

为什么decorator不能装饰静态方法或类方法?

from decorator import decorator

@decorator
def print_function_name(function, *args):
    print '%s was called.' % function.func_name
    return function(*args)

class My_class(object):
    @print_function_name
    @classmethod
    def get_dir(cls):
        return dir(cls)

    @print_function_name
    @staticmethod
    def get_a():
        return 'a'

get_dir 和 get_a 的结果都是 AttributeError: <'classmethod' or 'staticmethod'>, object has no attribute '__name__'。

为什么decorator 依赖属性__name__ 而不是属性func_name? (Afaik 所有函数,包括 classmethods 和 staticmethods,都具有 func_name 属性。)

编辑:我使用的是 Python 2.6。

【问题讨论】:

  • 你为什么在装饰器内部调用函数(*args)?它的工作是简单地返回一个函数(在你的情况下,未修改)。
  • gahooa:因为这是“装饰器”(他导入的内容,而不是语言结构)的一种工作方式,请参阅pypi.python.org/pypi/decorator。
  • @taldor 你在 py 2.6 中有装饰器模块吗?
  • @mykhal:我单独安装的。

标签: python decorator


【解决方案1】:

classmethod 和 staticmethod 返回 descriptor objects,而不是函数。大多数装饰器并非设计为接受描述符。

通常,在使用多个装饰器时,您必须最后应用classmethod 和staticmethod。而且由于装饰器是按“自下而上”的顺序应用的,classmethod 和 staticmethod 通常应该在源代码的最顶层。

像这样:

class My_class(object):
    @classmethod
    @print_function_name
    def get_dir(cls):
        return dir(cls)

    @staticmethod
    @print_function_name
    def get_a():
        return 'a'

【讨论】:

    【解决方案2】:

    当 @classmethod 和 @staticmethod 是最顶层的装饰器时,它可以工作:

    from decorator import decorator
    
    @decorator
    def print_function_name(function, *args):
        print '%s was called.' % function.func_name
        return function(*args)
    
    class My_class(object):
        @classmethod
        @print_function_name
        def get_dir(cls):
            return dir(cls)
        @staticmethod
        @print_function_name
        def get_a():
            return 'a'
    

    【讨论】:

    • 作为一项规则,classmethod 和 staticmethod 使用一种特殊的魔法并且必须最后调用。
    • 请记住,这不是 100% 可互换的。向上移动内置装饰器可能会影响结果方法本身的特性,例如如果print_function_name 是一个装饰类,则结果方法的突出类型将受到覆盖的内置装饰器的影响
    【解决方案3】:

    这是你想要的吗?

    def print_function_name(function):
        def wrapper(*args):
            print('%s was called.' % function.__name__)
            return function(*args)
        return wrapper
    
    class My_class(object):
        @classmethod
        @print_function_name
        def get_dir(cls):
            return dir(cls)
    
        @staticmethod
        @print_function_name
        def get_a():
            return 'a'
    

    【讨论】:

    • 我不确定您是否意识到,但他使用的“装饰器”包与带有“包装器”的构造执行相同的操作。您的 sn-ps 之间的唯一区别是在 My_class 中应用装饰器的顺序。您可能会在答案中澄清这一点,以解释为什么它可以解决问题。
    • 感谢您的更正。我在 py3k 中解决了这个问题,其中缺少装饰器模块。我的意思是我的回复是快速的,并且确信有人会发布更好的答案并提供详细的解释
    • @(Peter Hansen) .. 然而,python 2.6 中也没有装饰器模块
    猜你喜欢
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 2016-02-17
    • 2011-09-18
    • 2011-11-16
    • 2011-12-08
    • 2014-01-03
    相关资源
    最近更新 更多