从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__
定制普通类的实例。