python中object/type/metaclass

object关键词说起


官方文档上这样定义object:

1
2
Any data with state (attributes or value) and defined behavior (methods).
Also the ultimate base class of any new-style class.

具有状态(属性和值)以及定义了行为(方法)的数据就是object。同时object是所有新式类的最根本的基类。利用object这样定义(新式)类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class MyClass(object):
def __init__(self, *args, **kwargs):
print 'new self id:', id(self)
id(MyClass):
>>> 48438744L
id(object)
>>> 506057936L
type(MyClass)
>>> <type 'type'>
isinstance(MyClass, type)
>>> True

MyClass即为静态定义(运行前就定义好了)的类,它继承于object,也因此获得了object的一些属性和方法,包括魔术方法。python中的类的最大特色在于其也是一个对象(实例)。每个类存在于内存中,是object的子类,type的实例。

实例通过__init__函数进行初始化,一般将此作用的方法称为构造函数。但是python中的__init__还不能完全称为构造函数。很明显,在__init__运行前,实例就存在了,即传入的self参数。实例这个对象在__init__运行前就被解释器按照object的内存模型分配好了内存,进行了一番装饰。

1
2
3
4
5
6
7
8
9
i = MyClass()
>>> new self id: 42531472L
id(i)
>>> 42531472L
ii = MyClass()
>>> new self id: 34971944
id(ii)
>>> 34971944L

通过上面这个例子看到self这个参数就是python解释器已经初步实例化了的实例,也可以看到在__init__函数被调用前就已经存在了。因此python有另外一个魔术方法__new__,可以真正的定制实例的内存模型(创建一个什么样的实例)。下面的例子更能说明这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class MyClass(object):
def __new__(cls, *args, **kwargs):
instance = super(MyClass, cls).__new__(cls)
#或者写成
#instance = object.__new__(cls)
return instance
def __init__(self, *args, **kwargs):
print 'new self id:', id(self)
i = MyClass()
>>> new self id: 69858136
id(i)
>>> 69858136L
class MyInt(object):
def __new__(cls, *args, **kwargs):
instance = int.__new__(cls) # 用int的模型构造实例
instance.to_str = lambda self: str(self)
return instance
m = MyInt(1)
m
>>> 1
m.to_str()
>>> '1'

MyClass与之前的定义没有区别。不过通过自定义的__new__函数可以在实例存在之前介入,直接操纵实现什么样的实例,并且还能够给实例赋予一些属性和方法。
MyInt的定义就更加明显,虽然没有继承于int,但是在__new__函数中直接操纵其实例按照int的模型构造,并且赋予了实例一个方法to_str。结果MyInt类就和直接继承int没有明显的区别。python中的单例模式可以更好的说明:

1
2
3
4
5
6
7
8
9
10
11
class Singleton(object):
instance = None
def __new__(cls, *args, **kwargs): # __init__不能够做到这一点,因为在调用之前,实例就存在了
if not cls.instance:
cls.instance = super(Singleton, cls).__new__(cls)
return cls.instnace
s1 = Singleton()
s2 = Singleton()
s1 is s2 # 同一个实例
>>> True

可以看到,通过__new__可以从一开始就定制如何实现实例(其内存模型)。

type的传说


python中一切皆对象。一切都是其基类的实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
isinstance(1, int) -> True
isinstance(int, type) -> True
isinstance(type, type) -> True
isinstance('abc', str) -> True
issubclass(str, basestring) -> True
isinstance(basestring, type) -> True
isinstance(type, type) -> True
isinstance(object, type) ->True
class MyClass(object):
pass
i = MyClass()
isinstance(i, MyClass) -> True
issubclass(MyClass, object) -> True
isinstance(MyClass, type) -> True

object是新式类的根本基类;type则是所有超类的根本基类,甚至是它自己的基类。MyClasstype的实例,当MyClass被定义的时候(python解释器编译这段代码时)就是实例化的过程。可以理解为,python解释器定义了一个变量为MyClass,它是type的实例。而type这种能够用来定义类的类则称为超类metaclass

前面说过,MyClass是静态定义的类,在运行前就定义好了属性和方法。python提供了type关键字用于动态定义类。按照python文档的说明,下面两种定义类的方式是等价的。

1
2
3
4
class MyClass(object):
pass
MyClass = type('MyClass', (object,), {}) # 第二个参数必须是 tuple类型

通过实例化type,python提供了一种动态创建类的方式。type(name, bases, attrs),第一个name参数给定类的名字MyClass.__name__属性,第二个参数bases给定继承的多个基类,第三个参数attrs确定MyClass的一些属性和方法。由于type能够定义类,那么所有继承type的类,也就有了type这种神奇的定义类的功能,从而成为超类。

普通类可以在定义时通过__new__函数操纵生成的实例,所有继承type的超类也可以通过__new__来操纵生成的类(超类的实例)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MetaClass(type): # 超类继承type,普通类继承object
def __new__(cls, name, bases, attrs):
print 'name:', name
print 'bases:', bases
print 'attrs:', attrs
new_class = super(MetaClass, cls).__new__(cls, name, bases, attrs)
return new_class
MyClass = MetaClass('MyClass', (object,), {}) # 手动实例化实现MyClass
>>> name: MyClass
>>> bases: (object,)
>>> attrs: {}
i = MyClass()
print type(i)
>>> <class '__main__.MyClass'>
isinstance(i, MyClass) -> True
isinstance(MyClass, MetaClass) -> True

MetaClass也具有了type的能力。但是,这样通过超类动态实现MyClass需要额外的手动实例化,非常的不协调。python提供了另一种方法,通过定义__metaclass__属性,让解释器实现这一过程。

1
2
3
4
5
6
7
8
9
10
class MyClass(object):
__metaclass__ = MetaClass
cls_var = 'var'
def method(self): pass
>>> name: MyClass
>>> bases: (object,)
>>> attrs: {'cls_var': 'var', 'method': <function m at 0x000000000437E588>, \
'__module__': '__main__', '__metaclass__': <class '__main__.MetaClass'>}

当类或者基类的属性中有__metclass__时,会调用__metaclass__进行类本身的生成,而不是默认的类生成过程。类自己的内存模型通过定义__metaclass__可以动态定制,其实例可以通过定义__new__函数实现定制。进行类定制的超类继承于type,通过定义__new__函数实现。

可以简单总结为:超类继承于type,通过__new__定制超类的实例,即普通类;普通类继承于object,通过__new__定制普通类的实例。