一、继承
1. python中的继承分为:单继承、多继承
class P1: pass class P2: pass class Son1(P1): #单继承 pass class Son2(P1,P2): #多继承 pass
子类继承了父类所有的属性,当子类与父类属性重名时,子类先在自己的属性列表中查找
class Dad: money=10 def __init__(self,name): print('父类') self.name=name class Son(Dad): pass #子类中没有__init__函数,所以从父类中继承了这个函数
s1=Son('alex') #父类
print(s1.name) #alex
print(s1.money) #10
2. 什么时候用继承
当类之间有明显不通,并且较小的类是较大的类所需要的组件时,用组合
当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承
3. 接口继承
定义一个基类,基类中将自己的方法用装饰器的方式定义成接口函数,这样,只要是基类的子类,就必须在子类中实现这个方法,否则在生成实例时就会报错
归一化:接口继承实质上是要求:做出一个良好的抽象,这个抽象规定了一个兼容的接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象
import abc class All_file(metaclass=abc.ABCMeta): @abc.abstractmethod def Read(self): #基类中定义的方法不用实现,目的只是为了规范子类 pass @abc.abstractmethod def Write(self): pass class AAA(All_file): def Read(self): print('Read') def Write(self): print('Write')
4. 继承顺序
python如果继承了多个类,那么寻找方法有2种:深度优先、广度优先
经典类继承顺序按深度优先
新式类继承顺序按广度优先
深度优先继承顺序为 F --> D --> B --> A --> E --> C
广度优先继承顺序为 F --> D --> B --> E --> C --> A
对于定义的每个类,python会计算一个解析顺序MRO列表,这个列表就是一个简单的所有基类的线性继承顺序 F.__mro__()
继承的三条原则:
1. 子类会先于父类被检查
2. 多个父类会根据他们在mro列表中的顺序被检查
3. 如果对下一个类存在两个合法的选择,选择第一个父类
父类是新式类,则子类也是新式类
5、子类中调用父类的方法
class Vehicle: country='China' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('Run') class Subway(Vehicle): def __init__(self,name,speed,load,power,line): Vehicle.__init__(self,name,speed,load,power) #调用父类的__init__并添加其他逻辑 self.line=line def show_info(self): print(self.name) def run(self): Vehicle.run(self) #调用父类的run函数并添加其他逻辑 print('%s%s号线开通啦!'%(self.name,self.line)) p1=Subway('南京地铁','100KM/H',1000,2000,'line10') p1.run()
#Run
#南京地铁line10号线开通啦!
上述方法,若有一天,基类的类名被修改了,那么所有调用基类的子类中,都需要手动修改基类名,繁琐
类提供了一个super函数:
class Vehicle: country='China' def __init__(self,name,speed,load,power): self.name=name self.speed=speed self.load=load self.power=power def run(self): print('Run') class Subway(Vehicle): def __init__(self,name,speed,load,power,line): super().__init__(name,speed,load,power) #super()相当于super(Subway.self) self.line=line def show_info(self): print(self.name) def run(self): super().run() #使用super函数,不用再传self print('%s%s号线开通啦!'%(self.name,self.line)) p1=Subway('南京地铁','100KM/H',1000,2000,'line10') p1.run()
二、多态
多态:由不同的类实例化得到的对象调用同一个方法,执行的逻辑不同
多态的概念指出了对象如何通过他们共同的属性和动作来操作和访问,而不需要考虑他们具体的类
class H2O: def __init__(self,name,temperature): self.name=name self.temperature=temperature def turn_ice(self): if self.temperature<0: print('%s温度太低结冰了'%self.name) if self.temperature>100: print('%s温度太高变成了水蒸气'%self.name) if self.temperature>0 and self.temperature<100: print('%s液化成了水'%self.name) class Water(H2O): pass class Ice(H2O): pass class Steam(H2O): pass w1=Water('水',50) I1=Ice('冰',-20) S1=Steam('水蒸气',200) w1.turn_ice() I1.turn_ice() S1.turn_ice()
#水液化成了水
#冰温度太低结冰了
#水蒸气温度太高变成了水蒸气
类的继承有两层意义:1改变,2扩展
多态就是这两层意义的一个具体的实现机制
即:调用不同的类实例化的对象下的相同方法,实现的过程不一样
三、封装
第一个层面:类就是一个麻袋,这本身就是一种封装
第二个层面:类中定义私有的,只在类内部使用,外部无法访问
'''方法一:定义时,使用单下划线开头,约定单下划线开头的不在类外部使用 但实际上外部仍然可以调用''' class AAA: _star='earth' def __init__(self,name): self.name=name p1=AAA('alex') print(p1._star) #earth '''方法二:使用双下划线开头 在类外面调用双下划线开头的会报错,因为类自动将__star重命名为_类名__star,类外部__类名__star仍然可以调用''' class AAA: __star='earth' def __init__(self,name): self.name=name p1=AAA('alex') #print(p1.__star) #报错 print(p1._AAA__star) #earth
第三个层面:明确区分内外,内部逻辑外部无法知晓。并且为封装到内部的逻辑提供一个方法接口,给外部使用
class People: __star='earth' def __init__(self,id,name,age,salary): print('--->',self.__star) self.name=name self.id=id self.age=age self.salary=salary def __get_id(self): print('我是私有方法,我找到的ID是%s'%self.id) def get_star(self): #定义一个访问函数 print(self.__star) self.__get_id() p1=People(1234,'alex',25,1000) p1.get_star()
面向对象的优点:
1. 通过封装明确了内外
2. 通过继承+多态在语言层面支持了归一化设计