python __new__和__metaclass__
先说__new__
__new__
原型为object.__new__(cls,[...])
,cls是一个类对象。当你调用C(*arg, **kargs)
来创建一个类C的实例时。python内部调用是C.__new__(C, *arg, **kargs)
,然后返回值是类C的实例c。在确认c是C的实例后,python再调用C.__init__(c, *arg, **kargs)
来实例化c
1class Person(object):
2 def __new__(cls, name, age):
3 print '__new__ called.'
4 return super(Person, cls).__new__(cls, name, age)
5
6 def __init__(self, name, age):
7 print '__init__ called.'
8 self.name = name
9 self.age = age
10
11 def __str__(self):
12 return '<Person: %s(%s)>' % (self.name, self.age)
13
14if __name__ == '__main__':
15 piglei = Person('piglei', 24)
16 print piglei
__new__
方法主要是当你继承一些不可变的class时(比如int, str, tuple), 提供给你一个自定义这些类的实例化过程的途径。还有就是实现自定义的metaclass
比如这样是没效果的
1class PositiveInteger(int):
2 def __init__(self, value):
3 super(PositiveInteger, self).__init__(self, abs(value))
这样才行
1class PositiveInteger(int):
2 def __new__(cls, value):
3 return super(PositiveInteger, cls).__new__(cls, abs(value))
使用__new__
可以实现单例模式
1class Singleton(object):
2 def __new__(cls):
3 if not hasattr(cls, 'instance'):
4 cls.instance = super(Singleton, cls).__new__(cls)
5 return cls.instance
或者
1class Singleton(object):
2 _singleton = {}
3
4 def __new__(cls):
5 if not cls._singleton.has_key(cls):
6 cls._singleton[cls] = object.__new__(cls)
7 return cls._singleton[cls]
下面是__metaclass__
“元类就是深度的魔法,99%的用户应该根本不必为此操心。如果你想搞清楚究竟是否需要用到元类,那么你就不需要它。那些实际用到元类的人都非常清楚地知道他们需要做什么,而且根本不需要解释为什么要用元类。” —— Python界的领袖 Tim Peters
比如我们想给python的list增加一个add
方法,实现append
方法的功能的时候,我们可以这样
1class MyList(list):
2 def add(self, value):
3 self.append(value)
还可以这样
1class ListMetaclass(type):
2 def __new__(cls, name, bases, attrs):
3 attrs['add'] = lambda self, value: self.append(value)
4 return type.__new__(cls, name, bases, attrs)
5
6class MyList(list):
7 __metaclass__ = ListMetaclass
在这里面也能看出来__new__
方法接受的参数是四个,而前面用到的一般只使用了cls一个参数
对于
1class Foo(Bar):
2 pass
Python做了如下的操作:
Foo中有__metaclass__
这个属性吗?如果是,Python会在内存中通过__metaclass__
创建一个名字为Foo的类对象(我说的是类对象,请紧跟我的思路)。如果Python没有找到__metaclass__
,它会继续在Bar(父类)中寻找__metaclass__
属性,并尝试做和前面同样的操作。如果Python在任何父类中都找不到__metaclass__
,它就会在模块层次中去寻找__metaclass__
,并尝试做同样的操作。如果还是找不到__metaclass__
,Python就会用内置的type来创建这个类对象。
所以类的父类的__metaclass__
是会被调用两次的,也就是说metaclass可以隐式地继承到子类,但子类自己却感觉不到。比如
1class ListMetaclass(type):
2 def __new__(cls, name, bases, attrs):
3 print name
4 attrs['add'] = lambda self, value: self.append(value)
5 return type.__new__(cls, name, bases, attrs)
6
7class MyList(list):
8 __metaclass__ = ListMetaclass
9
10
11class MyList1(MyList):
12 pass
13
14l = MyList1()
15l.add(2)
可以发现输出为
1MyList
2MyList1
使用__metaclass__
实现的一个简单的orm
1class User(Model):
2 # 定义类的属性到列的映射:
3 id = IntegerField('id')
4 name = StringField('username')
5 email = StringField('email')
6 password = StringField('password')
7
8
9class Model(dict):
10 __metaclass__ = ModelMetaclass
11
12 def __init__(self, **kw):
13 super(Model, self).__init__(**kw)
14
15 def __getattr__(self, key):
16 try:
17 return self[key]
18 except KeyError:
19 raise AttributeError(r"'Model' object has no attribute '%s'" % key)
20
21 def __setattr__(self, key, value):
22 self[key] = value
23
24 def save(self):
25 fields = []
26 params = []
27 args = []
28 for k, v in self.__mappings__.iteritems():
29 fields.append(v.name)
30 params.append('?')
31 args.append(getattr(self, k, None))
32 sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
33 print('SQL: %s' % sql)
34 print('ARGS: %s' % str(args))
35
36
37class ModelMetaclass(type):
38 def __new__(cls, name, bases, attrs):
39 # 还是上面的原因 Mode类不需要调用这个__new__
40 if name=='Model':
41 return type.__new__(cls, name, bases, attrs)
42 mappings = dict()
43 # attrs的内容是{'password': <__main__.StringField object at 0x7fb405714c10>...}等
44 for k, v in attrs.iteritems():
45 if isinstance(v, Field):
46 print('Found mapping: %s==>%s' % (k, v))
47 mappings[k] = v
48 # 删除这些类属性 防止访问实例属性的时候发生错误,因为实例属性优先级大于类属性
49 for k in mappings.iterkeys():
50 attrs.pop(k)
51 # 假设表名和类名一致
52 attrs['__table__'] = name
53 # 保存属性和列的映射关系
54 attrs['__mappings__'] = mappings
55 return type.__new__(cls, name, bases, attrs)
本文参考