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

python 学习笔记 元类 ORM

2015-01-26 11:43 363 查看
4:定制类:
__len__() 作用于len() 函数
__slots__ 限制动态绑定属性
__str__ () __repr__()相当于java的tostring()函数 不过__str__()是用户看到的字符串 后者是调试服务的字符串
>>>class Student(object):
def __init__(self,name):
self.name=name
def __str__(self):
return 'Student object (name:%s)' % self.name
>>>print Student('lc')
Student objcet(name:lc)
>>>s=Student('lc')
>>>s
<__main__.Student object at 0x131ad23d> #这时就需要更改__repr__()函数

__iter__().如果想要被for...in循环遍历 就必须实现 __iter__()这个方法 该方法返回一个迭代对象 Python for 循环就会不断调用迭代对象的next()方法拿到下一个值 直到遇到StopIteration
异常

>>>class Fib(objcet):
def __init__(self):
self.a,self.b=0,1#初始化两个计数器a和b
def __iter__(self):
return self #实例本是就是迭代对象 故返回自己
def next(self):
self.a,self.b=self.b,self.a+self.b #计算下一个值
if self.a>100000:#退出循环条件
raise StopIteration()
return self.a #返回下一个值
>>>for i in Fib():
print i
1
1
2
.......

__getitem__: 上述实例 Fib 虽然能过用于for...in 循环 但是却没有办法像list那样按照下标取元素 这就需要用到 __getitem__()方法:
>>>class Fib(object):
def __getitem__(self,n):
a,b=1,1
for x in range(n):
a,b=b,a+b
return a
>>>f=Fib()
>>>f[0]
1
>>>f[3]
3
但是这样 对于 切片却不可用 原因是 切片传入的是切片对象 slice
>>>class Fib(object):
def __getitem__(self,n):
if isinstance(n,int):
a,b=1,1
for x in range(n):
a,b=b,a+b
return a
if isinstance(n,slice):
start=n.start
stop=n.stop
a,b=1,1
L=[]
for x in range(stop):
if x>=start:
L.append(a)
a,b=b,a+b
return L
>>>f=Fib()
>>>f[0:5]
[1,1,2,3,5]
这样就实现了切片 但是没有对step的处理 也没有负数的处理

__getattr__(). 本来如果调用了对象不存在的属性就会报错 但是 写上 __getattr__()之后 解释器就会尝试从这个方法中获得属性的值
>>>class Student(object):
def __init__(self):
self.name='lc'
def __getattr()__(self,attr):
if attr=='score':
return 99
raise AttributeErrors('has no this attr')
>>>s = Student()
>>>s.score
99

__call__() 让对象本身相当于一个方法一样被调用
>>>class Student(object):
def __init__(self,name):
self.name=name
def __call__(self):
print self.name
>>>s=Student('lc')
>>>s()
lc
__call()__还可以定义参数 这样就可以把对象像一个函数一样调用 Callable() 函数可以判断一个对象是否可以被调用。

5:使用元类:
动态语言和静态语言最大的不同 就是函数和类的定义 不是编译时定义的 而是运行时动态创建的
class 的定义是运行时动态创建的 而创建class 的方法就是使用type()函数
type()函数既可以返回一个对象模型 又可以创建出新的类型 比如我们通过 type()函数创建hello类 而无需通过 class Hello(objec)...定义
>>>def fn(self,name='world'):
print ('Hello,%s.' % name)
>>>Hello=type('Hello',(object,),dict(hello=fn))
>>>h = Hello()
>>>h.hello()
Hello World
>>>print(type(Hello))
<type 'type'>
>>>print(type(hello))
<class '__main__.Hello'>
该函数三个参数:
1:class的名称
2:继承的父类的集合 Python是多继承 只有一个元素的时候 不要忘记tuple的单元素的写法
3:class的方法名称与函数绑定 这里把 fn绑定到了方法名hello上面
通过type创建的类与直接定义是一样的 本质上是通过动态创建的

metaclass: 控制类的创建行为 元类::当我们创建类的时候我们就可以通过这个类来创建对象实例,当时同样的 如果我们想创建类 那么就必须根据这个metaclass 来创建类
也就是说 我们需要先定义metaclass 才能够创建类。
>>># metaclass 是创建类 也就是需要根据创建类来创建类 所以必须从type类型派生
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 来创建类
当我们写下 __metaclass__=ListMetaclass 的时候 Python解释器就会 知道 当我们创建MyList类的时候 要通过ListMetaclass.__new__()来创建 在此处可以修改类的定义
比如加上新的方法 然后返回修改后的定义

__new__()方法接受的参数依次是:
1:当前准备创建的类的对象:
2:类的名称
3:类继承的父类集合
4:类的方法集合

>>>L=MyList()
>>>L.add(1)
>>>L
[1]

而普通的list没有add()方法
>>>l=list
>>>l.add(1)
Traceback........

所谓存在即为合理 ,那么动态修改定义的类中的定义有什么意义呢?
ORM模型 对象关系模型 就是把关系型数据库的一行映射为一个对象 也就是一个类定义一个表
要编写一个ORM框架 所有的类都只能够动态的定义 因为只有使用者才能够根据表的结构动态的定义出对应的类来
>>>class User(Model):
#定义类的属性到列的映射
id=IntegerField('id')
name=StringField('name')
email=StringField('email')
password=StringField('password')
#创建一个实例
u=User(id=12345,name='lc','email=1023948@qq.com',password='my-pwd')
#保存到数据库
u.save()
用户这样User想要通过这个类操作数据库的User表 父类的Model和属性类型 StringField IntegerField是由ORM提供的 设下的比如save方法都是有metaclass自动完成的
>>>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)
>>>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')
>>>class ModeMetaclass(type):
def __new__(cls,name,bases,attrs):
if name='Model':
return type.__new__(cls,name,bases,attrs)
mappings=dict()
for k,v in attrs.iteritems():
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)
>>>class Model(dict):
__metaclass__=ModelMetaclass

def __init__(self,**kw):
super(Model,self).__init__(**kw)

def __getattr(self,key):
try:
return self[key]
except keyError:
raise AttributeError(r''
'Model' object has no attribute '%s' '' % key)

def __setattr__(self,key,value):
sef[key]=value

def save(self):
field=[]
params=[]
args=[]
for k,v in self.__mappiings__.iteritems():
fields.append(v.name)
params.append('?')
args.append(getattr(self,k,None))
sql ='insert into %s
(%s) values (%s)' %(self.__table__,','.join(fields),','.join(params))
print('SQL:%s' % sql)
print('ARGS: %s' %
args) .
当用户定义一个class User(Model) 的时候 Python解释器会首先在当前类User中查找__metaclass__ 如果没有找到 就继续在父类Model中查找__metaclass__找到了就使用model中定义的__metaclass__的ModelMetaclass来创建User类
也就是说,metaclass可以隐式的继承到子类,但是子类感觉不到。
在ModelMetaclass中一共做了几件事情:
1:排除掉对Model类的修改:
2:在当前类(比如User)中查找定义的类的所有属性,如果找到一个Field属性,就把它保存到一个__mapping__的dict中,同时从类的属性中删除该Field属性 否则 容易出现运行时错误
3:把表名 保存到__table__中 这里简化的认为表名就是类名
在model类中 就可以定义各种各样的操作数据库的方法 比如save() delete() find() update()
输出如下:
Found model:User
Found mapping:email==><StringField:email>
Found mapping:password==><StringField:password>
Found mapping:id==><IntegerField:uid>
Found mapping:name==><StringField:username>
SQL:insert into User(password,email,username,uid)
values(?,?,?,?)
ARGS:['my-pwd','93109219@qq.com','lc'12345]

类属性 和实例属性
直接在类中定义的属性就是类属性
>>>class Student(object):
name='Student'
实例属性必须通过实例来绑定 比如self.name='xxxx'
>>>s=Student()
>>>print(s.name)
Student
>>>print(Student.name)
Student
在实例中如果没有这个属性 就会打印类属性
>>>s.name='lc'
>>>s.name
lc
>>>Student.name
Student ..
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: