python类——黑板客老师课程学习 1、基本语法 2、属性和封装 3.方法 4、继承和组合 5、多态 6、元编程 7、wxpython

  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__

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

  可以看到:

    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这个属性。

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

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

 

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

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

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

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

     我们先用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'小明')

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

    这样有一个好处,就是我们在对他进行初始化的时候,也把也进入了__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://*.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__

      python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

       python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

 

4、继承和组合

4.1继承——简单例子

  python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

 

#!/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多重继承

  python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

  python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

  为什么会是这样呢?

  python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

 

  mro:method resolution order

    经典类(classic)是深度优先

    新式类(new)是广度优先

 

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

    经典类和新式类的区别:

      经典类定义A的时候

        python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

      新式类定义A的时候

        python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

4.3super继承

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

       python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

      python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

 

      python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

 

      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类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

      但是这样的方式让人看起来不舒服,于是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’,(),{})

      python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

     写法2

      class A(object):

        __metaclass__==simplemeta

      python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

      方法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’)                    

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

    python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

      为什么?

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

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

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

 

      python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

      因为__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

 

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

          python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

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

 

      元编程——ORM

        ORM:Object Relational Mapping对象关系映射

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

 

 

        python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython

 

      匹配由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

  python类——黑板客老师课程学习
1、基本语法
2、属性和封装
3.方法
4、继承和组合
5、多态
6、元编程
7、wxpython