首页 > 解决方案 > Python - 元类装饰器 - 如何使用 @classmethod

问题描述

我有以下 Python 元类,它deco_with_args为每个类添加了一个装饰器:

def deco_with_args(baz):
    def decorator(func):
        ...
        return func
    return decorator

class Foo(type):
    def __prepare__(name, bases):    
        return {'deco_with_args': deco_with_args}

这允许我像这样使用装饰器:

class Bar(metaclass=Foo):
    @deco_with_args('baz')
    def some_function(self):
        ...

如何使deco_with_args装饰器表现得像 an@classmethod以便我可以Bar从函数内访问该类(或任何其他类)decorator

我试过@classmethoddeco_with_args函数上使用没有运气。

标签: pythonpython-3.xpython-decoratorsmetaclassclass-method

解决方案


您的问题有两种解释-如果您需要在调用示例中cls命名的函数时可用decorator(即,您需要修饰的方法成为类方法),则将其本身转换为类方法就足够了:

def deco_with_args(baz):
    def decorator(func):
        ...
        return classmethod(func)
    return decorator

第二个是如果您需要在调用自身时cls可用deco_with_args,在创建装饰函数本身时,在类创建时。现在被列为已接受的答案列出了一个简单的问题:当类主体运行时,该类还不存在,因此,在解析类主体结束时,您不可能拥有将知道类本身。

但是,与该答案试图暗示的不同,这不是真正的交易。cls您所要做的就是在类创建过程结束时懒惰地运行您的装饰器代码(需要. 你已经有一个元类设置,所以这样做几乎是微不足道的,只需在你的装饰器代码周围添加另一个可调用层:

def deco_with_args(baz):
    def outter_decorator(func):
        def decorator(cls):
            # Code that needs cls at class creation time goes here
            ...

            return func
        return decorator
    outter_decorator._deco_with_args = True
    return outter_decorator

class Foo(type):
    def __prepare__(name, bases):    
        return {'deco_with_args': deco_with_args}

    def __init__(cls, cls_name, bases, namespace, **kwds):
        for name, method in cls.__dict__.items():
            if getattr(method, '_deco_with_args', False):
                cls.__dict__[name] = method(cls)

        super().__init__(cls_name, bases, namespace, **kwds)

当然,这将在类主体执行完成之后运行,但在class运行之后的任何其他 Python 语句之前。如果您的装饰器会影响在类主体内部执行的其他元素,那么您需要做的就是将它们包装起来以保证延迟执行。


推荐阅读