[Python] 深入理解元类并区分元类中的init、call、new方法

0. 参考书籍和元类的作用总结

本文内容参考书籍《流畅的Python》《Effective Python》《编写高质量代码:改善Python程序的91个建议》。我只是知识的搬运工,将知识进行整理,区分出其中的重点并加入自己的理解。感兴趣的最好去翻看原书的相关内容。

  1. 执行到类的代码体结束后时,会调用该类的元类中的__new____init__方法,利用这两个方法,可以对类做一些定制化的操作。
  2. 初始化类的实例时,会调动该类的元类中的__call__方法,利用这个方法,可以对类的实例对象做一下定制化的操作。
  3. 初始化类的实例时,__call____new____init__三个方法的执行顺序是 元类__call__、类的__new__、类的__init__

这三点参考 【6. 元类中的 init 、call、new 方法】,结合代码的执行顺序就可以理解了。

1. 元类的定义

元类是制造类的工厂,元类是用于构建类的类。 这句话很重要!!!这句话很重要!!!这句话很重要!!!

我们正常定义类是这样的:

class Person(object):
    pass

class Child(Person):
    ClassName = 'Child'
    def __init__(self, name, age):
        if age > 20:
            raise ValueError("Child's age must small than 20")
        self._name = name
        self._age = age

    def speak(self):
        print(self._name, self._age)

我们还可以使用 type 来动态创建类:

class Person(object):
    pass


ClassName = 'Child'
def __init__(self, name, age):
    if age > 20:
        raise ValueError("Child's age must small than 20")
    self._name = name
    self._age = age

def speak(self):
    print(self._name, self._age)

# type 的三个参数分别是 name、bases 和 dict。最后一个参数是一个映射,指定新类的属性名和值。
Child = type('Child', (Person,), {
   'ClassName': ClassName,
                                      '__init__': __init__,
                                      'speak': speak})
john = Child('John', 20)
john.speak()
print(Child.__dict__)  # 有 ClassName,__init__ 和 speak 属性

使用 type 关键字去拼接函数和属性来创建类,实在是不够优雅。之所以谈到这个,是为了方便我们后面理解元类是如何动态改变类的属性的。

2. 区分继承自 type 和使用 metaclass 关键字

元类从 type 类继承了构建类的能力。所有类都直接或间接地是 type 的实例,不过只有元类同时也是 type 的子类。搞清楚这句话,意思就是,元类是 type 类的子类。使用 metaclass 关键字的类并不是type 的子类。

class ClassOne(type):  # 这个是元类
    pass

class ClassTwo(metaclass=type):  # 不是元类,是用元类创建的类
    pass

class ClassThree(object, metaclass=type):   # 与ClassTwo一模一样。不是元类,是用元类创建的类
    pass

class ClassFour(ClassOne):  # 继承自元类,是元类
    pass

print(ClassOne.__mro__)
print(ClassTwo.__mro__)
print(ClassThree.__mro__)
print(ClassFour.__mro__)
(<class '__main__.ClassOne'>, <class 'type'>, <class 'object'>)
(<class '__main__.ClassTwo'>, <class 'object'>)
(<class '__main__.ClassThree'>, <class 'object'>)
(<class '__main__.ClassFour'>, <class '__main__.ClassOne'>, <class 'type'>, <class 'object'>)

一定要搞清继承自 type 和使用 metaclass 关键字的不同。前者是元类,后者是由元类创建的类。

3. 类装饰器的运行

为什么要讲类装饰器?因为类装饰器能以较简单的方式做到需要使用元类去做的事情 ——创建类时定制类。

类装饰器与函数装饰器非常类似,是参数为类对象的函数,返回原来的类或修改后的类。我们先来看代码,你可以尝试写一写答案:

"&#
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值