python 元类 metaclass:
metaclass 控制类的行为。当我们创建类的时候我们就可以通过这个类来创建对象实例,当然同样的,如果我们想要创建类,那么就必须根据这个metaclass来创建类,也就是说,我们需要先定义metaclass才能过创建类。
1:Python中类本省就是对象,类之所以为类,就是因为类这个对象本身拥有创建对象的能力。
于是我们可以对类进行1:将它赋值给一个变量,2:拷贝它,3:为它增加属性,4:作为参数进行传递。
因为类也是对象,所以我们可以在运行是动态的创建类。
def make_class():
class Foo(object):
pass
return Foo
myclass=make_class()
print myclass
#<class '__main__'.Foo>
当我们使用class关键字的时候,Python解释器会自动的为我们创建这个类对象,同时Python也提供手动处理是方法,这个方法就是type()。type()方法根据参数的不同有两种完全不一样的方法。1:type可以返回一个对象的类型是什么。2:type接受一个类的描述作为参数可以放回一个类。
>>> print type(1)
<type 'int'>
>>> print type('1')
<type 'str'>
>>> print type(myclass)
<type 'type'>
>>> print type(myclass())
<type '__main__.myclass'>
type可以像这样进行工作:
type(类名,父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))
比如:
>>> class myclass2(object):
... pass
可以这样手动创建
>>> myclass2=type('myclass2',(),{})
>>> print myclass2
<class '__main__.myclass2'>
>>> print myclass2()
<__main__.myclass2 object at 0x23291212>
同样你可以为其增加属性或者方法,为其继承:
>>> def echo_bar(self):
... print self.bar
>>>Foo=type('Foo',(),{'bar':True})
>>>Foo().bar
True
>>>Foo2=type('Foo2',(Foo,),{'echo_bar':echo_bar})
>>>Foo2().echo_bar()
True
元类就是用来创建这些类的类。元类是类的类,type就是Python在背后用来创建所有类的元类。Python中所有的东西都是对象,包括整数,字符串,等等,而且他们都是由一个类创建而来的:
>>> age=25
>>> age.__class__
<type 'int'>
>>> name ='bob'
>>> name.__class__
<type 'str'>
>>>def foo():pass
>>>foo.__class__
<type 'function'>
对于没有自定义元类的类来说,__class__属性的值都为 <type 'type'> .因为他们都是由元类type创建出来的。当然我们也可以自己创建元类。
__metaclass 字段:我们在写一个类的时候,可以为其添加一个__metaclass__属性 这样Python就会用__metaclass__指定的元类来创建这个类。
class Foo(object):
__metaclass__=something
首先Python会在类的定义中寻找__metaclass__属性,如果没有找到,则会用内建的type元类来创建这个类,否则用指定的元类来创建这个类。之后类对象才会在内存中创建。
元类的主要目的是为了在创建类的时候能够自动的改变类。一般在代码中metaclass类如下:
class ListMetaclass(type):
def __new__(cls,name,bases,attrs):
attr['add']=lambda self,value:self.append(value)
return type.__new__(cls,name,bases,attrs)
class Mylist(list):
__metaclass__=ListMetaclass #指示使用ListMetaclass 来创建类
这样Python解释器在创建类 Mylist的时候发现其有 __metaclass__属性 并且只为 ListMetaclass 于是用ListMetaclass这个元类来创建Mylist类。可以看到ListMetaclass这个元类继承了type 类 并且重写了 __new__方法,其有四个属性,但是type方法只有三个属性,这个很好理解:就像类中每个方法都会有一个self一样,cls 通用表示元类对象自身,
name:表示要创建的类名
bases:表示父类tuple
attr:表示属性,方法dict
所谓存在即为合理,orm关系模型就会用到动态修改类定义的方式,也就是元类。例如一下就是一个简单的orm框架
编写底层模块的第一步,就是先把调用接口写出来,比如想要定义一个User类来操作对应的数据库表User我们希望这样写:
class User(Model):
#定义类的属性到列的映射
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
#创建一个实例:
u = User(id=12345,name='Michael',email='test@orm.org',password='my-pwd')
u.save()
其中,父类Model和属性类型StringField IntegerField是又ORM框架提供,剩下的方法都是由metaclass完成。
首先定义field 类 负责保存数据库表的字段名和字段类型:
class Field(object):
def __init__(self,name,column_type):
self.name=name
self.column_type=column_type
def __str__(self):
return '<%s:%s>' % (self.__class__.__name__,self.name)
#__str__相当于java中的tostring方法 self.__class__返回创建这个对象的类
在field基础上编写 StringField IntegerField 等等
class StringField(Field):
def __init__(self,name):
super(StringField,self).__init__(name,'varchar(100)')
class IntegerField(Field):
def __init__(self,name):
super(IntegerField,self).__init__(name,'bigint')
然后就是modelMetaclass了
class ModelMetaclass(type):
def __new__(cls,name,bases,attrs):
if name=='Model':
return type.__new__(cls,name,bases,attrs)#不对Model类定义做任何修改
mappings = dict()
for k,v in attrs.iteritems():#k是属性名 v 是数据库列 Field
if isinstance(v,Field):
print('Found mapping :%s===>%s' % (k,v))
mappings[k]=v
for k in mappings.iterkeys():
attrs.pop(k) #从类属性中删除跟数据库对应的属性
attrs['__table__'] = name #假设类名和表名一致
attrs['__mappings__'] = mappings #保存属性和列的映射关系
return type.__new__(cls,name,bases,attrs)#调用父类的__new__方法创建类对象
class Model(dict):
__metaclass__=ModelMetaclass #指明用ModelMetaclass 元类来创建Model类
def __init__(self,**kw):
super(Model,self).__init__(**kw) #调用父类的方法也就是dict
def __getattr__(self,key): # model.key
try:
return self[key]
except KeyError:
raise AttributeError(r"'Model' object has no attribute '%s'" % key )
def __setattr__(self,key,value):#model.key = value
self[key] = value
def save(self):
fields=[]
params=[]
args = []
for k,v in self.__mappings__.iteritems():#保存属性和列的对应关系
fields.append(v.name) #列名
params.append('?')
args.append(getattr(self,k,None)) #如果不存在返回None
sql = 'insert into %s (%s) values (%s)' %(self.__table__,','.join(fields),','.join(params))
print ('SQL:%s' %sql)
print ('ARGS:%s' % str(args))
以上就实现了一个简单的orm模块