• python装饰器2:类装饰器


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

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

    类装饰器的形式

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

    @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)
    
  • 相关阅读:
    题解 CF432D 【Prefixes and Suffixes】
    题解 P3199 【[HNOI2009]最小圈】
    题解 AT1221 【水筒】
    题解 P4381 【[IOI2008]Island】
    题解 CF1242B 【0-1 MST】
    《数据库系统概论》 -- 3.1 SQL概论和DDL
    《数据库系统概论》 -- 2. 关系操作
    《数据库系统概论》 -- 1. 绪论
    配置vim成为IDE
    ubuntu--软件管理
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/10205168.html
Copyright © 2020-2023  润新知