本文介绍了Python-元类装饰器-如何使用@classmethod的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have the following Python metaclass that adds a deco_with_args decorator to each class:

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}

这使我可以像这样使用装饰器:

This allows me to use the decorator like this:

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

如何使deco_with_args装饰器的行为类似于@classmethod,以便可以从decorator函数中访问Bar类(或其他任何类)?

How do I make the deco_with_args decorator behave like an @classmethod so that I can access the Bar class (or whatever other class) from within the decorator function?

我尝试在deco_with_args函数上使用@classmethod时没有运气.

I have tried using @classmethod on the deco_with_args function with no luck.

推荐答案

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

There are two interpretations on your question - if you need cls to be available when the function named decorator in your example is called (i.e. you need your decorated methods to become class methods), it suffices that itself is transformed into a classmethod:

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

第二个是如果您需要cls在调用deco_with_args本身时,在创建修饰函数本身时,在类创建时可用.现在被列为已接受的答案列出了以下直接问题:运行类主体时该类尚不存在,因此,无法在解析该类结束时正文中,您可以拥有该类本身已知的方法.

The second one is if you need cls to be available when deco_with_args itself is called, when creating the decorated function itself, at class creation. The answer that is listed as accepted right now lists the straightforward problem with that: The class does not exist yet when the class body is run, so, there is no way that at the end of parsing the class body you can have methods that would have known of the class itself.

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

However, unlike that answer tries to imply, that is not a real deal. All you have to do is to run your decorator code (the code that needs the cls) lazily, at the end of the class creation process. You already have a metaclass setup, so doing this is almost trivial, by just adding another callable layer around your decorator-code:

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语句之前运行.如果您的装饰器会影响在类主体本身内部执行的其他元素,那么您所需要做的就是将它们包装起来以保证也可以进行延迟执行.

This will be run, of course, after the class body execution is complete, but before any other Python statement after the class is run.If your decorator would affect other elements that are executed inside the class body itself, all you need to do is to wrap those around to warrant a lazy-execution as well.

这篇关于Python-元类装饰器-如何使用@classmethod的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 10:28