python-33 面向对象之二:组合、继承
1.当类之间有显著的不同,并且较小的类是较大的类所需要的组件时,用组合较好
''' 1.组合:在一个类中以另外一个类的对象作为数据属性,称为类的组合 ''' class School: def __init__(self,name,add): self.name=name self.add=add class Course: def __init__(self,name,price,priod,school): self.name=name self.price=price self.priod=priod self.school=school #传入一个类,这样就构成了一个组合,一类中包含了另一个类 s1=School('清华','北京') s2=School('科大','合肥') c1=Course('python','1w','3mon',s1) #这就是组合,大类中包含小类 c2=Course('linux','2w','4mon',s2) print(c1.school.name) print(s1,'\n',c1.__dict__['school'])#打印 s1内存地址,地址相同
2.当类之间有许多共同的功能,提取这些共同的功能做基类,用继承较好
继承:具有两方面含义,一是继承父类的特性,二是具有自己衍生的特性
单继承:从上往下继承,先继承祖先类,再继承子孙类的类数据属性和方法属性,实例化时,先查找自己的__init__方法,没有再往上找,直到找到为止,
如果都没有显示的__init__方法,调用object类的__init__方法
class A: print('---A---') def __init__(self,name): self.name=name print('A:name=%s'%self.name) def eat(self): print('%s正在吃ing'%self.name) class B(A): a=1 print('---B---') class C(B): print('---C---') def __init__(self,sex,age): self.g=super().__init__('小a') self.sex=sex self.age=age print('C:sex=%s age=%s'%(sex,age)) c=C('boy',50)#先打印 B C类的数据属性,相当于先将打印的代码加载到C类中,再调用父类的__init__,最后是自身的__init__方法 c.eat()#小a正在吃ing print(c.__dict__)#{'name': '小a', 'g': None, 'sex': 'boy', 'age': 50},拥有了name数据属性
多继承:根据mro线性顺序表继承(广度优先查找),同样先继承所有父类的数据属性,再查找__init__,调用了哪个父类的__init__方法,就继承了该父类的所有其它方法属性,未被调用的父类,则不继承该父类的方法属性。
''' 1.组合:在一个类中以另外一个类的对象作为数据属性,称为类的组合 ''' class School: def __init__(self,name,add): self.name=name self.add=add class Course: def __init__(self,name,price,priod,school): self.name=name self.price=price self.priod=priod self.school=school #传入一个类,这样就构成了一个组合,一类中包含了另一个类 s1=School('清华','北京') s2=School('科大','合肥') c1=Course('python','1w','3mon',s1) #这就是组合,大类中包含小类 c2=Course('linux','2w','4mon',s2) print(c1.school.name) print(s1,'\n',c1.__dict__['school'])#打印 s1内存地址,地址相同 ''' 2. 继承:新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类的继承分为:单继承和多继承 ''' class Father: money=100 #继承类的属性和方法 def __init__(self,name): self.name=name print('这是爸爸【name=%s】类'%self.name) def Habit(self): print('爸爸【name=%s】的坏习性:爱抽烟'%self.name) def work(self): print('Father教学生') class Mother: car='路虎' def __init__(self,age,national ): self.age=age self.national=national print('这是妈妈【age=%d】类'%self.age) def Hobby(self): print('妈妈【age=%d】的爱好是打球'%self.age) class Son(Father,Mother): #可以多继承,但实例化时,若自身没有__init__,则调用第一个父类的__init__,即Father.__init__ def work(self): print('Son开汽车') print(Father.__dict__) print(Mother.__dict__) print(Son.__dict__) #不包含父母类的任何属性{'__module__': '__main__', 'work': <function Son.work at 0x000000000225A0D0>, '__doc__': None} f=Father('大明')#创建Father对象,调用__init__实例化一个f对象,返回:这是爸爸【name=大明】类 m=Mother(30,'美国人')# 这是妈妈【age=30】类 print(Son.__base__)#__base__只查看从左到右继承的第一个父类,<class '__main__.Father'> print(Son.__bases__)#__bases__,查看所有父类,(<class '__main__.Father'>, <class '__main__.Mother'>) s=Son('小明')#先调用自己的__init__,没有则调用继承的第一个父类,Father.__init__实例化一个s对象,故返回:这是爸爸【name=小明】类, print(s.name,s.car,s.money)#能调用父母类的静态数据属性,小明 路虎 100 s.Habit()#能调用父类的方法属性,爸爸【name=小明】的坏习性:爱抽烟 s.work()#Son开汽车---->方法名相同,并不会改写父类的方法, f.work()#Father教学生---->父类方法不变 s.Hobby()#出错,AttributeError: 'Son' object has no attribute 'age',因为实例化时调用的是第一个父类Father.__init_
class Grandpa: language='英语' def tell(self): print('Grandpa会讲%s'%self.language) class Son1(Grandpa,Mother): def job(self): print('Son1 is a driver') s1=Son1(15,'中国') s1.Hobby()#这是妈妈【age=15】类,妈妈【age=15】的爱好是打球,Grandpa类没有.__init__,就调用Mother.__init__ print(Son1.mro())#继承顺序:[<class '__main__.Son1'>, <class '__main__.Grandpa'>, <class '__main__.Mother'>, <class 'object'>]
总结:类中的方法属性都是与具体对象绑定的,而数据属性无具体对象绑定,所以,在多继承中,只有实例化了父类,即调用了父类的__init__方法后,才能调用该父类的其它方法属性,而没 有被实例化的父类,则不会继承其方法属性,但具有其数据属性。至于@staticmethod的类工具包,既不绑定类又不绑定对象的方法属性,是能继承的。@classmethod,类方法,也是被类继承。