骏马金龙 (新博客:www.junmajinlong.com)

网名骏马金龙,钟情于IT世界里的各种原理和实现机制,强迫症重症患者。爱研究、爱翻译、爱分享。特借此一亩三分田记录自己成长点滴!!!

python装饰器2:类装饰器

分类: python

本文是装饰器相关内容的第二篇,关于类装饰器。

"类装饰器"有两种解读方式:用来装饰类的装饰器;类作为装饰器装饰其它东西。你如何认为取决于你,两种说法都有出现在其它的文章中。我的文章中是将"类装饰器"解读为第一种方式,即装饰类的东西。而“类作为装饰器装饰其它东西”,我都会为其标注"类作为装饰器"或"作为装饰器的类"以避免歧义。

类装饰器的形式

函数装饰器是装饰函数(方法)的,类装饰器是装饰类的,它们的表现形式是一样的。

@decorator
class cls:
    ...

c = cls()

等价于:

class cls:
    ...

cls = decorator(cls)

c = cls()

它的效果是创建实例对象的时候,会触发装饰器中的代码逻辑。

再细细一想,发现decorator(cls)要返回的是一个类,所以decorator中的结构大概是这样的:

def decorator(cls):
    class wrapper:
        ...
    return wrapper

这样就会让被包装的类cls实际变成wrapper类,并且以后调用cls构造对象的时候,实际上是调用wrapper类来构造对象。换句话说,wrapper已经拦截了对所有的cls操作。

但并非一定如此,比如直接返回原始的cls:

def decorator(cls):
    ...do something about cls...
    return cls

这种方式比较简单,本文主要对前一种方式进行详细解释。

由于返回的是class wrapper,那么它装饰类的时候,假设所装饰的类有构造方法__init__,构造方法中有属性,这个类中还有方法。如下:

@decorator
class cls():    # 等价于cls = decorator(cls)
    def __init__(self, x, y):
        self.attrx = x
        self.attry = y
    def method(self):
        return self.x, self.y

那么在包装器wrapper中,需要能够构造出这个对象,并且能够取得被包装类的对象属性、类属性。如下:

def decorator(cls):
    class wrapper():
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)
    return wrapper

因为操作cls类的时候,实际上是在操作wrapper类。所以构造cls对象的时候:

c = cls(3, 4)

实际上是在调用wrapper(3, 4)来构造对象,所以会执行wrapper里的__init__。但类装饰器最终的目标是为了扩展类cls,所以在wrapper里必须得构造出cls的对象。上面采取的方式是通过cls()来构造cls对象,并放在wrapper对象的一个属性wrapped中。

因为cls已经被金蚕脱壳成了wrapper,所以要获取到cls的属性必须在wrapper中重写属性获取的方式。

下面是一个示例:

def decorator(cls):
    class wrapper():
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def __getattr__(self, name):
            return getattr(self.wrapped, name)
    return wrapper

@decorator
class cls():
    def __init__(self, x, y):
        self.attrx = x
        self.attry = y
    def method(self):
        return self.attrx, self.attry

c = cls(3, 4)
print(c.attrx)
print(c.attry)
print(c.method())

输出结果:

3
4
(3, 4)

 

转载请注明出处:https://www.cnblogs.com/f-ck-need-u/p/10205168.html

如果觉得文章不错,不妨给个打赏,写作不易,各位的支持,能激发和鼓励我更大的写作热情。谢谢!

posted @   骏马金龙  阅读(7534)  评论(3编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
# 本文目录:
(右下角 # 关闭目录)
类装饰器的形式
点击右上角即可分享
微信分享提示

感谢您的支持

扫描二维码打赏

支付宝打赏