问题描述
我有以下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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!