python 学习笔记 元类 ORM

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   ..
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值