从object关键词说起
官方文档上这样定义object:
|
|
具有状态(属性和值)以及定义了行为(方法)的数据就是object。同时object是所有新式类的最根本的基类。利用object这样定义(新式)类:
|
|
MyClass即为静态定义(运行前就定义好了)的类,它继承于object,也因此获得了object的一些属性和方法,包括魔术方法。python中的类的最大特色在于其也是一个对象(实例)。每个类存在于内存中,是object的子类,type的实例。
实例通过__init__函数进行初始化,一般将此作用的方法称为构造函数。但是python中的__init__还不能完全称为构造函数。很明显,在__init__运行前,实例就存在了,即传入的self参数。实例这个对象在__init__运行前就被解释器按照object的内存模型分配好了内存,进行了一番装饰。
|
|
通过上面这个例子看到self这个参数就是python解释器已经初步实例化了的实例,也可以看到在__init__函数被调用前就已经存在了。因此python有另外一个魔术方法__new__,可以真正的定制实例的内存模型(创建一个什么样的实例)。下面的例子更能说明这一点:
|
|
MyClass与之前的定义没有区别。不过通过自定义的__new__函数可以在实例存在之前介入,直接操纵实现什么样的实例,并且还能够给实例赋予一些属性和方法。MyInt的定义就更加明显,虽然没有继承于int,但是在__new__函数中直接操纵其实例按照int的模型构造,并且赋予了实例一个方法to_str。结果MyInt类就和直接继承int没有明显的区别。python中的单例模式可以更好的说明:
|
|
可以看到,通过__new__可以从一开始就定制如何实现实例(其内存模型)。
type的传说
python中一切皆对象。一切都是其基类的实例。
|
|
object是新式类的根本基类;type则是所有超类的根本基类,甚至是它自己的基类。MyClass是type的实例,当MyClass被定义的时候(python解释器编译这段代码时)就是实例化的过程。可以理解为,python解释器定义了一个变量为MyClass,它是type的实例。而type这种能够用来定义类的类则称为超类metaclass。
前面说过,MyClass是静态定义的类,在运行前就定义好了属性和方法。python提供了type关键字用于动态定义类。按照python文档的说明,下面两种定义类的方式是等价的。
|
|
通过实例化type,python提供了一种动态创建类的方式。type(name, bases, attrs),第一个name参数给定类的名字MyClass.__name__属性,第二个参数bases给定继承的多个基类,第三个参数attrs确定MyClass的一些属性和方法。由于type能够定义类,那么所有继承type的类,也就有了type这种神奇的定义类的功能,从而成为超类。
普通类可以在定义时通过__new__函数操纵生成的实例,所有继承type的超类也可以通过__new__来操纵生成的类(超类的实例)。
|
|
MetaClass也具有了type的能力。但是,这样通过超类动态实现MyClass需要额外的手动实例化,非常的不协调。python提供了另一种方法,通过定义__metaclass__属性,让解释器实现这一过程。
|
|
当类或者基类的属性中有__metclass__时,会调用__metaclass__进行类本身的生成,而不是默认的类生成过程。类自己的内存模型通过定义__metaclass__可以动态定制,其实例可以通过定义__new__函数实现定制。进行类定制的超类继承于type,通过定义__new__函数实现。
可以简单总结为:超类继承于type,通过__new__定制超类的实例,即普通类;普通类继承于object,通过__new__定制普通类的实例。