zoukankan      html  css  js  c++  java
  • python类——黑板客老师课程学习

    1、基本语法

      class class_name(base_class):  base_class是它继承的父类

        class_var

        def methods(self,args):

          statements

     

      经典类、新式类

      版本2和版本3的区别,3都是新式类

       首先,写法不一样:

        class A: #旧式类
            pass
    
        class B(object): #新式类
            pass

      经典类和新式类的区别:

        1__slots__,

        新式类里有这个,‘槽’的意思,对属性的一个限制,只能访问槽里边的属性。

        2)继承顺序,super

        3__new__,

        4)__getattribute__

        

        

      可以看到:

        1.A的属性比较少,B的属性比较多。

        2.A可以对__slots__以外的属性赋值,B不可以。因为Python是动态的,所以可以随便往里边添加属性,但是如果有了槽之后,即有了__slots__之后,只能添加槽里边有的

        东西。三个引号包括的内容在help帮助里边会显示。我们写程序的时候尽量用新式类。

    2、属性和封装

    2.1实例属性和类属性

    class Car(object):
        country=u’中国’ #类属性
        def __init__(self,length,width,height,owner=None):  #定义实例属性
            self.owner=owner
            self.length=length
            self.width=width
            self.height=heigth                            

      实例属性一般定义再__init__里边,比如上边的self.owner,self.length,self.width,self.height。类属性一般定义在方法外边,比如上边的country属性。

     

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke
    
    class Car(object):
        country = u'中国'
        def __init__(self, length, width, height, owner=None):
            self.owner = owner
            self.length = length
            self.width = width
            self.height = height
            self.country = "china"
    
    if __name__ == '__main__':
        a = Car(1.2,1.4,1.5,u'黑板客')
        b = Car(2.2,2.4,2.5,u'小张')
        print a.owner, b.owner
        print a.country, b.country #country访问的是实例属性
    
        b.country = u'美国' #改变的是实例属性
    
        print a.country, b.country #输出实例属性
        print Car.country #输出类属性
    
        print "--------------------------"
        del a.country #删除a的实例属性
        print a.country#因为a的实例属性别删除了,所以会找类属性,所以输出的是类属性
        #del a.country
        #del Car.country
        #print a.country

    输出为:

    >>> 
    黑板客 小张
    china china
    china 美国
    中国
    --------------------------
    中国
    >>> 

      当我们调用a.country时,先去实例属性中找,如果有,就用实例属性的,如果没有就找类属性的。当我们用Car.country的时候,我们调用的类属性。

      当我们把acountry删除之后,a的在实例属性中找不到,就会到类属性中找。而bcountry没有删除,所以直接就用实例属性中的country

    2.2私有属性

        不能直接访问。对类自己可见,对外不可见的。

        目的:保证赋值的合理性。

        两种做法:

          1.__xxx  两个下划线,不能直接访问到,但可以间接访问到

          2._xxx  一个下划线,可以直接访问到,但是有一个下划线提示我们直接访问是不合理的,实际上是自己提醒自己的方式

          __xxx__    两边都有两个下划线,这是系统自带的属性。

     

          _xxx 不能用于’from module import *’ 以单下划线开头的表示的是protected类型的变量。即保护类型只能允许其本身与子类进行访问。

          __xxx 双下划线的表示的是私有类型的变量。只能是允许这个类本身进行访问了。连子类也不可以

          __xxx__定义的是特列方法。像__init__之类的,是系统定义的名字,我们应该避免这样命名变量

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke
    
    class Car(object):
        country = u'中国'
        def __init__(self, length, width, height, owner=None):
            self.__owner = owner#双下划綫,不可以直接访问
            
            assert length>0,"length must larger than 0"
            #单下划线,可以直接访问,但是此时已经提醒作者,不应该直接访问的,作者自己监督
            self._length = length
            self._width = width
            self._height = height
    
        def getOwner(self):
            return self.__owner
        def setOwner(self, value):
            self.__owner = value
    
        def getLength(self):
            return self._length
            
        def setLength(self,value):
            assert value>0,"length must larger than 0"
            self._length = value
    
    if __name__ == '__main__':
        a = Car(1.2,1.4,1.5,u'黑板客')
        print a.getOwner()
    
        #a.setLength(-1)

     

    2.3装饰器描述符

        描述符——定义了getset的一个对象。

        编程描述符有什么好处:像取属性一样操作方法,把方法当做属性去访问

        a.setlength(-1)  这是直接用getset方法定义的方法

        a.length=-1   这是用描述符实现的

        用法:

        

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke
    
    class Car(object):
        country = u'中国'
        def __init__(self, length, width, height, owner=None):
            self._owner = owner
            self._length = length
            self._width = width
            self._height = height
    
        @property #相当于get方法
        def owner(self):
            return self._owner
        @owner.setter #相当于set方法
        def owner(self, value):
            self._owner = value
        @owner.deleter  #相当于delete方法
        def owner(self):
            self._owner = None
        
        @property
        def length(self):
            return self._length
        @length.setter
        def length(self, value):
            assert value>0,"length must larger than 0"
            self._length = value
    
    if __name__ == '__main__':
        a = Car(1.2,1.4,1.5,u'黑板客')
        print a.owner
        del a.owner
        print a.owner
        a.length=-1

     

    输出:

    >>> 
    黑板客
    None
    
    Traceback (most recent call last):
      File "C:UsersshiyeAppDataLocalTempproperty03.py", line 36, in <module>
        a.length=-1
      File "C:UsersshiyeAppDataLocalTempproperty03.py", line 28, in length
        assert value>0,"length must larger than 0"
    AssertionError: length must larger than 0
    >>> a.length=-1

        @property   get方法

        @owner.setter   set方法

        @owner.deleter   delete方法

        但是出现了一个新的问题,造成了代码的冗余,因为我们每一个属性,都要定义三个这样的方法,非常的麻烦

     

     2.4__getattr__

        __getattr__ ——特殊方法

          自动调用

          当访问一个属性,访问不到时,它会自动调用。

        __setattr__

          给属性赋值的时候自动调用

        __delattr__

          删除属性的时候自动调用

                                                                                                                                                 

       

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke
    
    class Car(object):
        country = u'中国'
        __slots__=('length','width','height','owner','__dict__')
        
        def __init__(self, length, width, height, owner=None):
            self.owner = owner
            self.length = length
            self.width = width
            self.height = height
            
        def __getattr__(self,name):
            print "__getattr__",name
            return self.__dict__.get(name,None)
            
        def __setattr__(self,name,value):
            print "__setattr__",name
            if name!='owner':
                assert value>0, name+" must larger than 0"
            self.__dict__[name]=value
            
        def __delattr__(self,name):
            print "__delattr__",name
            if name=='owner':
                self.__dict__[name]=None
    
                
    if __name__ == '__main__':
        a = Car(1.2,1.4,1.5,u'黑板客')
        """
        print a.owner
        del a.owner
        print a.owner
        a.length=1
        
        print a.country
        a.country = 'china'
        print a.country
        """
        #a.name = u"一汽"

    输出:

    >>> 
    __setattr__ owner
    __setattr__ length
    __setattr__ width
    __setattr__ height
    >>> a.name
    __getattr__ name
    >>> a.lenth=a
    __setattr__ lenth
    >>> a.length=-4  
    __setattr__ length
    
    Traceback (most recent call last):
      File "<pyshell#2>", line 1, in <module>
        a.length=-4
      File "C:/Users/shiye/Documents/set.py", line 22, in __setattr__
        assert value>0, name+" must larger than 0"
    AssertionError: length must larger than 0
    >>> __getattr__ __members__
    __getattr__ __methods__
    del a.length
    __delattr__ length
    >>> del owner
    
    Traceback (most recent call last):
      File "<pyshell#4>", line 1, in <module>
        del owner
    NameError: name 'owner' is not defined
    >>> del a.owner
    __delattr__ owner
    >>> 

    发现没有name属性,会调用__getattr__ 函数,其他的都一样。

     

        我们可以看到,我们只是产生了一个a,然后赋值的时候全部都调用了__setattr__,

        而且我们可以在这个地方对我们要赋的值就行判断,这样就免除了在每一次赋值的时候 都要判断的麻烦。

        如果我们用__slot__之后,就不会有__dict__这个东西了,就意味着无法再往里边添加__slot__以外的属性了,但是当我们把__dict__这个东西加进__slot__之后,我们,我们依然可以添__slot__以外的属性。比如上边的例子a.name这个属性。

        

        当我们调用a.mm的时候,因为不存在这个属性,所以会自动调用__getattr__

        这样我们就通过这些解决了,我们在设置属性时要对属性进行判断的一个过程。

     

        但是我们为什么要用__slots____dict__一起来配合使用呢?

        在__slots__里边加上__dict__之后,无法限制对属性的访问。如果没有slots的话,只有没有的属性才会调用__getattr__,有的属性就不会调用。而如果加上__slots__

        话,slots里边有的也会调用__getattr__

        

        但是这样也会有新的问题出现,如何控制对属性的赋值呢,可以用下边的方法:

        

         我们先用assert判断一下访问的属性是否在slots里边,然后再判断,__setattr__和__delete__也要这么做

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke
    
    class Car(object):
        country = u'中国'
        __slots__=('length','width','height','owner','__dict__')
        
        def __init__(self, length, width, height, owner=None):
            self.owner = owner
            self.length = length
            self.width = width
            self.height = height
            
        def __getattr__(self,name):
            print "__getattr__",name
            assert name in self.__slots__, "Not have this attribute "+name
            return self.__dict__.get(name,None)
            
        def __setattr__(self,name,value):
            print "__setattr__",name
            assert name in self.__slots__, "Not have this attribute "+name
            
            if name!='owner':
                assert value>0, name+" must larger than 0"
            self.__dict__[name]=value
            
        def __delattr__(self,name):
            print "__delattr__",name
            assert name in self.__slots__, "Not have this attribute "+name
            if name=='owner':
                self.__dict__[name]=None
    
    if __name__ == '__main__':
        a = Car(1.2,1.4,1.5,u'黑板客')
        """
        print a.owner
        del a.owner
        print a.owner
        a.length=1
        
        print a.country
        a.country = 'china'    
        print a.country
        
        a.name = u"一汽"
        """

        大多数的时候,我们是这么用__getattr__的,,比如getattr(a,’length’)是在我们运行程序的时候才决定我们要访问哪一个属性。

        

     

    2.5描述符

        非数据描述符定义了一个函数:__get__

        数据描述符定义两个函数:__get__    __set__

     

        描述符可以用作描述类的属性的这样的一个东西。当你定义了__get__    __set__,之后,这个类就可以作为另一个类的属性。

        举例:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke
    
    class PositiveNum(object):
        def __init__(self,value):
            self.val = value
     
        def __get__(self, instance, owner):
            # instance = a,b
            # owner = Car
            print "__get__",instance,owner
            return self.val
     
        def __set__(self, instance, value):
            # instance = a,b
            print "__set__",instance,value
            try:
                assert int(value)>0
                self.val = value
            except AssertionError:
                print "ERROR: "+str(value)+" is not positive number."
            except:
                print "ERROR: "+str(value)+" is not number value."  
                
        def __delete__(self,instance):
            print "__delete__",instance
            self.val = None
    
        #def __getattribute__(self,name):
            #print self, name
            
    class Car(object):
        country = u'中国'
        length = PositiveNum(0)
        width = PositiveNum(0)
        height = PositiveNum(0)
        #__slots__=('owner','length','width','height')
        
        def __init__(self, length, width, height, owner=None):
            self.owner = owner
            self.length = length
            self.width = width
            self.height = height
            
    
    
    if __name__ == '__main__':
        a = Car(1.2,1.4,1.5,u'黑板客')
        b = Car(2.2,2.4,2.5,u'小明')

        

        这样有一个好处,就是我们在对他进行初始化的时候,也把也进入了__init__里边对值进行了判断,免除了前边讲的冗余的问题。但是从运行结果上看,我们知道a.length

      b.length是一样的,为什么呢?因为length是个类属性。我们上边定义的那个类PositiveNum,里边有__set____get__函数,所以它不再是一个实例变量而是一个类变量。

     

     

        怎么解决这个问题呢?

     

        针对类修改PositiveNum

    class PositiveNum(object):
        def __init__(self):
            self.default = 1
            self.data = {}
     
        def __get__(self, instance, owner):
            # instance = x
            # owner = type(x)
            print "__get__",instance,owner
            return self.data.get(instance, self.default)
     
        def __set__(self, instance, value):
            # instance = x
            print "__set__",instance,value
            try:
                assert int(value)>0
                self.data[instance] = value ###针对instance进行赋值,不同的instance有不同的值,这样就保证了是实例变量而不是类变量
            except AssertionError:
                print "ERROR: "+str(value)+" is not positive number."
            except:
                print "ERROR: "+str(value)+" is not number value."
                
        def __delete__(self,instance):
            print "__delete__",instance
            del self.data[instance]

        实际上data是一个字典,我们针对不同的instance进行输出。但是也有一个问题,这个时候我们可以对a.x这样的属性进行赋值,实际上我们不想这样的,怎么办呢?我们可

        以在Car类里边加上__slots__进行限制。

        另外新式类里边多了一个__attribute__的描述符。在访问属性的时候就会被调用,所以调用的时机比较多。一般来说我们很少用的,如果改变了它,会考虑很多情况,因为

        许多情况它都会被调用的。

     

     

    3.方法

        分类   

          类方法   @classmethod

          实例方法

          静态方法  @staticmethod

          特殊方法(魔法方法)  __init__

     

        

     

     

     

          

            形式上的区别:

              1、调用是通过类和实例进行的,不能直接调用

              2、有自己的特殊参数 self   cls

              3、有自己的声明语法@classmethod  @staticmethod  __xx__()

     

              实质的区别:——绑定

     

              类方法——绑定类

              实例方法——绑定实例

              静态方法——和函数没有区别,无绑定

              特殊方法——在某些场合自动调用

     

     

        方法和函数的区别:

              函数(function)就相当于一个数学公式,它理论上不与其它东西关系,它只需要相关的参数就可以。所以普通的在module中定义的称谓函数是很有道理的。

               方法是与某个对象相互关联的,也就是说它的实现与某个对象有关联关系。这就是方法。虽然它的定义方式和函数是一样的。也就是说,在Class定义的函数

                就是方法。

     

            静态方法和实例方法的区别主要体现在两个方面:

     

              1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以

                无需创建对象。

              2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。

              3. 类方法可以被对象调用,也可以被实例调用;传入的都是类对象,主要用于工厂方法,具体的实现就交给子类处理

              4. 静态方法参数没有实例参数 self, 也就不能调用实例参数

            静态方法和类方法的区别:

              逻辑上类方法应当只被类调用,实例方法实例调用,静态方法两者都能调用。主要区别在于参数传递上的区别,实例方法悄悄传递的是self引用作为参数,而

              类方法悄悄传递的是cls引用作为参数。静态方法无隐含参数,主要为了类实例也可以直接调用静态方法。

    #!/usr/bin/env python
    # coding: utf-8
    # http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod-for-beginner
    
    class Date(object):
        #self 作为实例参数
        def __init__(self, day=0, month=0, year=0):
            self.day = day
            self.month = month
            self.year = year
            
        def __str__(self):#用于输出的时候显示内容
            return "{0}-{1}-{2}".format(self.year, self.month, self.day)
    
       # cls作为类方法的参数
        @classmethod
        def from_string(cls, date_as_string):
            year, month, day = map(int, date_as_string.split('-'))
            date1 = cls(day, month, year)
            return date1
    
        #静态方法,用类还是用实例都可以访问,这里没有self或者cls作为参数
        @staticmethod
        def is_date_valid(date_as_string):
            year, month, day = map(int, date_as_string.split('-'))
            return day <= 31 and month <= 12 and year <= 3999  
    
        @staticmethod
        def millenium(month, day):
            return Date(month, day, 2000) #返回的是Date对象
            
            
    class DateTime(Date):
    
        #特殊方法,当我们print一个类的时候,按照__str__的方式显示出来
        def __str__(self):
            return "{0}-{1}-{2} - 00:00:00PM".format(self.year, self.month, self.day)  
    
                
    if __name__=="__main__":
        
        s='2012-09-11'
        if Date.is_date_valid(s):
            date1 = Date.from_string('2012-09-11')
            print date1
            date2 = DateTime.from_string('2012-09-11')
            print date2
            
        millenium_new_year1 = Date.millenium(1, 1)
        print millenium_new_year1
        
        millenium_new_year2 = DateTime.millenium(10, 10)
        print millenium_new_year2

     输出:

    >>> 
    2012-9-11
    2012-9-11 - 00:00:00PM
    2000-1-1
    2000-10-10
    >>> 

        特殊方法

          属性访问:__getattr__,__setattr__,__getattribute__

          实例生成/类生成:__init__,__new__

          数字计算:__add__,__sub__,__mul__,__div__,__pow__,__round__

          调用方法:__str__,__repr__,__lent__,__bool__    可以通过函数调用的方式,比如str()的方式调用,不需要用类或者实例的方式

          比较大小:__cmp__,__lt__,__le__,__eq__,__ne__,__gt__,__ge__

          集合访问:__setslice__,__getslice__,__getitem__,__setitem__,__contains__

          迭代器: __iter__,__next__

          

           

     

    4、继承和组合

    4.1继承——简单例子

      

     

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke 
    
    class Employee(object):
        def __init__(self, name, job=None, pay=0): # class = data + logic
            self._name = name
            self._job = job
            self._pay = pay
        def giveRaise(self, percent):
            self._pay = int(self._pay * (1 + percent))
        def __str__(self):
            return '[Employee: %s, %s, %s]' % (self._name, self._job, self._pay)
    
    
    class Manager(Employee):
        def __init__(self, name, pay): # Redefine constructor
            Employee.__init__(self, name, 'mgr', pay)
        def giveRaise(self, percent, bonus=.10):
            Employee.giveRaise(self, percent + bonus)
    
    if __name__ == '__main__':
        a=Employee("xiaoli",'sw_engineer',10000)
        b=Employee("xiaowang",'hw_engineer',12000)
        c=Manager("xiaozhang",8000)
    
        members=[a,b,c]
    
        for member in members:
            member.giveRaise(0.1)
            print member
        

    输出:

    >>> 
    [Employee: xiaoli, sw_engineer, 11000]
    [Employee: xiaowang, hw_engineer, 13200]
    [Employee: xiaozhang, mgr, 9600]
    >>> c.__class__
    <class '__main__.Manager'>
    >>> c.__class__.__base__
    <class '__main__.Employee'>
    >>> c.__class__.__base__.__base__
    <type 'object'>
    >>> c.__class__.__base__.__base__.__base__
    >>> 

    4.2多重继承

      

      

      为什么会是这样呢?

      

      我们导入inspect来查看一下D优先继承哪些类。可以看到BAC的顺序

     

      mro:method resolution order

        经典类(classic)是深度优先

        新式类(new)是广度优先

     

        

        由于我们定义的是经典类,所以D先继承了B,然后继承A,然后继承C。(深度优先)

        经典类和新式类的区别:

          经典类定义A的时候

            

          新式类定义A的时候

            

    4.3super继承

          当我们有多重继承的时候,会导致父类别多次调用了。

           

          

          为了解决这个问题,在新式类中我们引进了super关键字(super只在新式类中有),避免父类的多次调用。

     

          

     

          super是一个类,不是一个函数,调用规则:

          super(D,self).test()

    不使用super的情况:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke  
    
    class A:
        def test(self):
            print "A's test"
    
    class B(A):
        def test(self):
            print "B's test"
            A.test(self)
            #super(B,self).test()
        
    class C(A):
        def test(self):
            print "C's test"
            A.test(self)
            
    class D(B,C):
        def test(self):
            print "D's test"
            B.test(self) 
            C.test(self)
        
    if __name__=="__main__":
        a=D()
        a.test()

    输出:

    >>> ================================ RESTART ================================
    >>> 
    D's test
    B's test
    A's test
    C's test
    A's test
    >>> 

    使用super的情况:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke  
    
    class A(object):
        def test(self):
            print "A's test"
    
    class B(A):
        def test(self):
            print "B's test"
            super(B,self).test()
        
    class C(A):
        def test(self):
            print "C's test"
            super(C,self).test()
            
    class D(B,C):
        def test(self):
            print "D's test"
            super(D,self).test()
    
        
    if __name__=="__main__":
        a=D()
        a.test()

    输出:

    >>> ================================ RESTART ================================
    >>> 
    D's test
    B's test
    C's test
    A's test
    >>> 

        

    4.4组合

          把已有的类变成新的类属性。

          通过已有的类生成新类。

           

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    #copyRight by heibanke 
    
    class Employee(object):
        def __init__(self, name, job=None, pay=0): # class = data + logic
            self._name = name
            self._job = job
            self._pay = pay
        def giveRaise(self, percent):
            self._pay = int(self._pay * (1 + percent))
        def __str__(self):
            return '[Employee: %s, %s, %s]' % (self._name, self._job, self._pay)
    
    
    class Manager(Employee):
        def __init__(self, name, pay): # Redefine constructor
            super(Manager,self).__init__(name, 'mgr', pay)
        def giveRaise(self, percent, bonus=.10):
            super(Manager,self).giveRaise(percent + bonus)
    
    
    class Department(object):
        def __init__(self, *args):
            self.members = list(args)
    
        def addMember(self, person):
            self.members.append(person)
    
        def showAll(self):
            for person in self.members:
                print person 
        def giveRaise(self,percent):
            for person in self.members:
                person.giveRaise(percent)
    
    if __name__ == '__main__':
        a=Employee("xiaoli",'sw_engineer',10000)
        b=Employee("xiaowang",'hw_engineer',12000)
        c=Manager("xiaozhang",8000)
    
        d=Department(a,b,c)
    
        d.showAll()
        d.giveRaise(0.1)
        d.showAll()

    输出:

    >>> 
    [Employee: xiaoli, sw_engineer, 10000]
    [Employee: xiaowang, hw_engineer, 12000]
    [Employee: xiaozhang, mgr, 8000]
    [Employee: xiaoli, sw_engineer, 11000]
    [Employee: xiaowang, hw_engineer, 13200]
    [Employee: xiaozhang, mgr, 9600]
    >>> 

    5、多态

      多态是不同的类的相同的方法,相同的参数,不同功能。调用时便于将一组对象放在集合里,无需判断对象的具体类型,统一调用。

      里氏代换原则:

        父类出现的地方,子类一定可以出现,反之不一定。

      重载:相同的方法的不同的参数。对应Pythonargskwargs

      最典型的是运算符重载。

    6、元编程

      ——比较难,但是大部分不会用到它。

      元(meta

      语法——》语句

      类——》对象

      元类——》类

      元类就是生成类的类。通过元类来编程就是元编程。

      元编程——type

        type(name,bases,attrs)

        name:类名字符串

        bases:父类元组

        attrs:属性字典

     

        A=type(‘A’,(object,),{‘b’:1})

        a=A()

        print A, a.b

     

          c++python的类的概念是不一样的。c++的类就是语法,编译的时候类并没有生成,只是在语法上限制了一些东西。而Python是一个对象,是可以生成出来的,比如上边的A,是

        通过编程序生成出来的。在Python里边可以通过元类生成类。

          

          但是这样的方式让人看起来不舒服,于是Python提供另外一种方法:

     

    class simplemeta(type):
        def __init__(cls,name,bases,nmspc):
            super(simplemeta,cls).__init__(name,bases,nmspc)
            cls.uses_metaclass=lambda self:’yes’        


          写法1:

          A=simplemeta(‘A’,(),{})

          

          type也是一个类,类似于object类,type类里边的东西比object多一些。

         写法2

          class A(object):

            __metaclass__==simplemeta

          

          方法2中提供了__metaclass__的关键字,让我们很清楚的知道这就是一个元类。以后尽量用方法2来写。

     

          但是通过元类生成类和通过继承父类生成类有什么区别呢?

          元类和父类的区别:

            1、通过元类的初始化函数,或用metaclass关键字来生成新类

            2、通过继承父类来生成新类

     

          元类主要是定义类的行为,父类主要定义的是实例的行为。

      不可继承的类——最终类

    class final(type):
        def __init__(cls,name,bases,namespace):
            super(final,cls).__init__(name,bases,namespace)
            for klass in bases:
                if isinstance(klass,final):
                    raise TypeError(str(klass.__name__)+’is final’)                    

        当你想定义一个最终类的时候,加上这个元类就可以了。

        

          为什么?

          因为在finla类里边,有一些属性,因为Bfinal生成的,所以会在klaas里边,所以当我们运行的时候,isinstance会显示B是一个final,所以就raise TypeError(……)

          new的用途——新式类里边才会有的东西。

          __new____init__的区别:__new__是分配空间,__init__是配置参数,执行属性是先分配空间再配置参数。

     

          

          我们可以看到,第一个生成正整数没有成功,第二个成功了,为什么呢?

          因为__init__都已经配置好参数了,而对于int这种不可变的类型,你在对他改变是没有用的,而__new__只是分配好空间,没有产生什么值,所以就可以改变。

     

     

          单例模式中用__new__可以提前判断。

     

    class singleton(object):
        def __new__(cls):
            if now hasattr(cls):
                cls.instance=super(singleton,cls).__new__(cls)
            return cls.instance        

     

          元类的用法

            抽象函数——虚函数,在子类里实现。

            class MyAbstractClass(object):

              def method1(self):

                raise NotImplementedError(‘please Implement this method’)

              但是这样用有一个问题:如果我们没有实现里边方法,当我们不用这个方法的时候,不会报错,只有当子类使用这个方法的时候才会报错,所以我们一般用下

              边的方法,导进来一个abs的类。

            接口,由一组抽象函数组成的类

            from abs import ABCMeta,abstractmethod

            from MyAbstractClass2(object):

              __metaclass__=ABCMeta

              @bastractmethod

              def method1(self):

                pass

     

              按照这么实现,即使子类没有调用这个方法,如果他没有实现这个方法,也会报错。

              

              注意看注释信息,报错的时机不一样的。

     

          元编程——ORM

            ORM:Object Relational Mapping对象关系映射

            将数据库的操作用面向对象的程序方法实现。

     

     

            

     

          匹配由ORM来产生,我们只要生成类进行操作就行了。

          好处:

            1、易改:便于更新数据库,sql语句是由底层根据数据库类型生成的上层数据模型无需变化。

            2、易用:便于对数据模型进行操作,创建,更新,查询,删除。用户编写简单,无需写sql语句即可操作数据。

            3、易看:使数据模型的程序文档化。便于维护。

          缺点:

            不灵活,没有sql语句强大等。

            class user(model);

              id=integerField(’uid’)

              name=stringField(‘username’)

              email=stringField(‘email’)

              password=stringField(‘password’)

     

              u=user(id=12345,name=Michael,email=test@orm.org,password=my_pwd)

              u.save()

              具体内容可参考廖雪峰老师的博客学习相关的知识。

     

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001386820064557c69858840b4c48d2b8411bc2ea9099ba000
    
    
    ' Simple ORM using metaclass '
    
    __author__ = 'Michael Liao'
    
    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 ModelMetaclass(type):
    
        def __new__(cls, name, bases, attrs):
            print "name is ",name
            print "bases is ",bases
            print "attrs is ",attrs
            
            if name=='Model':
                return type.__new__(cls, name, bases, attrs)
            print('Found model: %s' % name)
            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['__mappings__'] = mappings # 保存属性和列的映射关系
            attrs['__table__'] = name # 假设表名和类名一致
            return type.__new__(cls, name, bases, attrs)
    
    class Model(dict):
        __metaclass__ = ModelMetaclass
    
        def __init__(self, **kw):
            print "Model instance __init__"
            super(Model, self).__init__(**kw)
    
        def save(self):
            fields = []
            params = []
            args = []
            for k, v in self.__mappings__.iteritems():
                fields.append(v.name)
                params.append('%s')
                args.append(self[k])
            sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(params))
            print('SQL: %s' % sql)
            print('ARGS: %s' % str(args))
    
        @classmethod
        def find_all(cls, *args):
    
    
            sql = 'select * from %s' % cls.__table__
            print('SQL: %s' % sql)
    # testing code:
    
    class User(Model):
        id = IntegerField('uid')
        name = StringField('username')
        email = StringField('email')
        password = StringField('password')
    
        
    u1 = User(id=12345, name='Michael', email='test1@orm.org', password='my-pwd')
    u2 = User(id=22345, name='Richael', email='test2@orm.org', password='my-pwd')
    u3 = User(id=32345, name='Hichael', email='test3@orm.org', password='my-pwd')
    
    u1.save()
    u2.save()
    u3.save()

    7wxpython

      

  • 相关阅读:
    3288 积木大赛
    3284 疯狂的黄大神
    1531 山峰
    1018 单词接龙
    1432 总数统计
    1507 酒厂选址
    1063 合并果子
    几个sort不能过的题目
    poj 2245 Lotto
    求两圆相交面积模板
  • 原文地址:https://www.cnblogs.com/shixisheng/p/5926353.html
Copyright © 2011-2022 走看看