python装饰器class_Python-元类装饰器-如何使用@classmethod

1586010002-jmsa.png

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):

...

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?

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

解决方案

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

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.

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)

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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值