您的位置:首页 > 编程语言 > Python开发

python 学习笔记 metaclass详解

2015-02-14 21:00 513 查看
python元类metaclass:
metaclass控制类的行为。当我们创建类的时候我们就可以通过这个类来创建对象实例,当然同样的,如果我们想要创建类,那么就必须根据这个metaclass来创建类,也就是说,我们需要先定义metaclass才能过创建类。

1:Python中类本省就是对象,类之所以为类,就是因为类这个对象本身拥有创建对象的能力

于是我们可以对类进行1:将它赋值给一个变量,2:拷贝它,3:为它增加属性,4:作为参数进行传递。



因为类也是对象,所以我们可以在运行是动态的创建类。

defmake_class():
classFoo(object):
pass
returnFoo
myclass=make_class()
printmyclass
#<class'__main__'.Foo>


当我们使用class关键字的时候,Python解释器会自动的为我们创建这个类对象,同时Python也提供手动处理是方法,这个方法就是type()。type()方法根据参数的不同有两种完全不一样的方法。1:type可以返回一个对象的类型是什么。2:type接受一个类的描述作为参数可以放回一个类。

>>>printtype(1)
<type'int'>
>>>printtype('1')
<type'str'>
>>>printtype(myclass)
<type'type'>
>>>printtype(myclass())
<type'__main__.myclass'>


type可以像这样进行工作:

type(类名,父类的元组(针对继承的情况,可以为空),包含属性的字典(名称和值))


比如:

>>>classmyclass2(object):
...pass


可以这样手动创建

>>>myclass2=type('myclass2',(),{})
>>>printmyclass2
<class'__main__.myclass2'>
>>>printmyclass2()
<__main__.myclass2objectat0x23291212>


同样你可以为其增加属性或者方法,为其继承:

>>>defecho_bar(self):
...printself.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'>
>>>deffoo():pass
>>>foo.__class__
<type'function'>


对于没有自定义元类的类来说,__class__属性的值都为<type'type'>.因为他们都是由元类type创建出来的。当然我们也可以自己创建元类。

__metaclass字段:我们在写一个类的时候,可以为其添加一个__metaclass__属性这样Python就会用__metaclass__指定的元类来创建这个类。

classFoo(object):
__metaclass__=something


首先Python会在类的定义中寻找__metaclass__属性,如果没有找到,则会用内建的type元类来创建这个类,否则用指定的元类来创建这个类。之后类对象才会在内存中创建。

元类的主要目的是为了在创建类的时候能够自动的改变类。一般在代码中metaclass类如下:

classListMetaclass(type):
def__new__(cls,name,bases,attrs):
attr['add']=lambdaself,value:self.append(value)
returntype.__new__(cls,name,bases,attrs)
classMylist(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我们希望这样写:

classUser(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和属性类型StringFieldIntegerField是又ORM框架提供,剩下的方法都是由metaclass完成。

首先定义field类负责保存数据库表的字段名和字段类型:

classField(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基础上编写StringFieldIntegerField等等

classStringField(Field):
def__init__(self,name):
super(StringField,self).__init__(name,'varchar(100)')
classIntegerField(Field):
def__init__(self,name):
super(IntegerField,self).__init__(name,'bigint')


然后就是modelMetaclass了

classModelMetaclass(type):
def__new__(cls,name,bases,attrs):
ifname=='Model':
returntype.__new__(cls,name,bases,attrs)#不对Model类定义做任何修改
mappings=dict()
fork,vinattrs.iteritems():#k是属性名v是数据库列Field
ifisinstance(v,Field):
print('Foundmapping:%s===>%s'%(k,v))
mappings[k]=v
forkinmappings.iterkeys():
attrs.pop(k)#从类属性中删除跟数据库对应的属性
attrs['__table__']=name#假设类名和表名一致
attrs['__mappings__']=mappings#保存属性和列的映射关系
returntype.__new__(cls,name,bases,attrs)#调用父类的__new__方法创建类对象


classModel(dict):
__metaclass__=ModelMetaclass#指明用ModelMetaclass元类来创建Model类
def__init__(self,**kw):
super(Model,self).__init__(**kw)#调用父类的方法也就是dict
def__getattr__(self,key):#model.key
try:
returnself[key]
exceptKeyError:
raiseAttributeError(r"'Model'objecthasnoattribute'%s'"%key)
def__setattr__(self,key,value):#model.key=value
self[key]=value
defsave(self):
fields=[]
params=[]
args=[]
fork,vinself.__mappings__.iteritems():#保存属性和列的对应关系
fields.append(v.name)#列名
params.append('?')
args.append(getattr(self,k,None))#如果不存在返回None
sql='insertinto%s(%s)values(%s)'%(self.__table__,','.join(fields),','.join(params))
print('SQL:%s'%sql)
print('ARGS:%s'%str(args))


以上就实现了一个简单的orm模块
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: