标签:数据 特定 实现继承 这不 opened 没有 之间 组合 含义
继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。子类会“遗传”父类的属性,从而解决代码重用问题。
# python中类的继承分为:单继承和多继承 class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 pass
class Dad: ‘这个是父类‘ money=10 def __init__(self,name): print(‘爸爸‘) self.name=name def hit_son(self): print(‘%s 正在打儿子‘ %self.name) class Son(Dad): pass print(Son.__bases__) # 查看所有继承的父类 s1=Son(‘lionel‘) print(s1.name) print(s1.money) s1.hit_son() """ (<class ‘__main__.Dad‘>,) 爸爸 lionel 10 lionel 正在打儿子 """
类的继承有两层意义:
import abc class All_file(metaclass=abc.ABCMeta): # 接口类,接口类的方法不需要实现,也不需要实例化 @abc.abstractclassmethod # 子类必须有read功能 def read(self): pass @abc.abstractclassmethod # 子类必须有write功能 def write(self): pass class Disk(All_file): def read(self): print(‘disk read‘) def write(self): print(‘disk write‘) class Cdrom(All_file): def read(self): print(‘cdrom read‘) def write(self): print(‘cdrom write‘) class Mem(All_file): def read(self): print(‘mem read‘) def write(self): print(‘mem write‘) m1=Mem() m1.read() m1.write() """ mem read mem write """
(1)实践中继承的第一种含义意义并不是很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。
(2)继承的第二种含义非常重要,又叫接口继承。接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”,这在程序设计上叫做归一化
Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是深度优先和广度优先。
class A: def test(self): print(‘A‘) class B(A): def test(self): print(‘B‘) class C(A): def test(self): print(‘C‘) class D(B): def test(self): print(‘D‘) class E(C): def test(self): print(‘E‘) class F(D,E): # def test(self): # print(‘F‘) pass f1=F() f1.test() # F-->D-->B-->E-->C-->A print(F.__mro__) # 查看继承顺序,只有新式才有这个属性可以查看线性列表,经典类没有这个属性 # 新式类继承顺序:F->D->B->E->C->A # 经典类继承顺序:F->D->B->A->E->C """ D (<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>) """
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如
>>> F.mro() #等同于F.__mro__ [<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>]
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
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(‘开动啦。。。‘) class Subway(Vehicle): def __init__(self,name,speed,load,power,line): Vehicle.__init__(self,name,speed,load,power) self.line=line def show_info(self): print(self.name,self.line) def run(self): Vehicle.run(self) print(‘%s %s号线 开动啦‘ %(self.name,self.line)) line8=Subway(‘北京地铁‘,‘10km/s‘,100000,‘电‘,8) line8.show_info() line8.run() """ 北京地铁 8 开动啦。。。 北京地铁 8号线 开动啦 """
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(‘开动啦。。。‘) class Subway(Vehicle): def __init__(self,name,speed,load,power,line): # Vehicle.__init__(self,name,speed,load,power) super().__init__(name,speed,load,power) self.line=line def show_info(self): print(self.name,self.line) def run(self): # Vehicle.run(self) super().run() print(‘%s %s线 开动啦‘ %(self.name,self.line)) line13=Subway(‘北京地铁‘,‘10km/s‘,100000,‘电‘,13) line13.show_info() line13.run() """ 北京地铁 13 开动啦。。。 北京地铁 13线 开动啦 """
由不同的类实例化得到的对象,调用同一个方法,执行的逻辑不同。多态指的是一类事物有多种形态,多态是一种反映在执行时候的一种状态。
class H2O: def __init__(self,name,temp): self.name=name self.temp=temp def turn_ice(self): if self.temp < 0: print(‘【%s】温度太低结冰了‘ %self.name) elif self.temp > 0 and self.temp < 100: print(‘【%s】液化为水‘ %self.name) elif self.temp > 100: print(‘【%s】温度太高变成水蒸气‘ %self.name) class Water(H2O): pass class Ice(H2O): pass class Steam(H2O): pass w1=Water(‘水‘,25) i1=Ice(‘冰‘,-25) s1=Steam(‘蒸汽‘,125) w1.turn_ice() i1.turn_ice() s1.turn_ice() """ 【水】液化为水 【冰】温度太低结冰了 【蒸汽】温度太高变成水蒸气 """
class H2O: def __init__(self,name,temp): self.name=name self.temp=temp def turn_ice(self): if self.temp < 0: print(‘【%s】温度太低结冰了‘ %self.name) elif self.temp > 0 and self.temp < 100: print(‘【%s】液化为水‘ %self.name) elif self.temp > 100: print(‘【%s】温度太高变成水蒸气‘ %self.name) class Water(H2O): pass class Ice(H2O): pass class Steam(H2O): pass w1=Water(‘水‘,25) i1=Ice(‘冰‘,-25) s1=Steam(‘蒸汽‘,125) def func(obj): obj.turn_ice() func(w1) func(i1) func(s1) """ 【水】液化为水 【冰】温度太低结冰了 【蒸汽】温度太高变成水蒸气 """
多态就是类的继承的两层意义的一个具体的实现机制,即调用不同的类实例化的对象下的相同的方法,实现的过程不一样。
Python不依赖语言特性去封装数据,而是通过遵循一定的数据属性和函数属性的命名约定来达到封的效果
class People1: star=‘earth‘ def __init__(self,id,name,age,salary): self.id=id self.name=name self.age=age self.salary=salary def get_id(self): print(‘我是私有方法,我找到的id是[%s]‘ %self.id) p1=People1(‘123‘,‘lonel‘,18,10000) p1.get_id() """ 我是私有方法,我找到的id是[123] """
# 定义者是以单下划线开头的,使用者就不应该调用它 class People2: _star=‘earth‘ def __init__(self,id,name,age,salary): self.id=id self.name=name self.age=age self.salary=salary def _get_id(self): print(‘我是私有方法,我找到的id是[%s]‘ %self.id) p1=People2(‘123‘,‘lonel‘,18,10000) p1._get_id() """ 我是私有方法,我找到的id是[123] """
class People3: __star=‘earth‘ def __init__(self,id,name,age,salary): self.id=id self.name=name self.age=age self.salary=salary def __get_id(self): print(‘我是私有方法,我找到的id是[%s]‘ %self.id) p1=People3(‘123‘,‘lionel‘,18,10000) # p1.__get_id() #报错,因为python将双下划线开头的名字重命名了 print(People3.__dict__) # 查看重命名后的名字为_People3__get_id p1._People3__get_id() """ {‘__module__‘: ‘__main__‘, ‘_People3__star‘: ‘earth‘, ‘__init__‘: <function People3.__init__ at 0x101d60488>, ‘_People3__get_id‘: <function People3.__get_id at 0x101d60598>, ‘__dict__‘: <attribute ‘__dict__‘ of ‘People3‘ objects>, ‘__weakref__‘: <attribute ‘__weakref__‘ of ‘People3‘ objects>, ‘__doc__‘: None} 我是私有方法,我找到的id是[123] """
class People4: __star=‘earth‘ def __init__(self,id,name,age,salary): self.id=id self.name=name self.age=age self.salary=salary def __get_id(self): print(‘我是私有方法,我找到的id是[%s]‘ %self.id) # 访问函数(接口函数) def get_star(self): print(self.__star) p1=People4(‘123‘,‘lionel‘,18,10000) p1.get_star() """ earth """
封装的真谛在于明确地区分内外,封装的属性可以直接在内部使用,而不能被外部直接使用,然而定义属性的目的终归是要用,外部要想用类隐藏的属性,需要我们为其开辟接口,让外部能够间接地用到我们隐藏起来的属性。
(1)封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制。
(2)封装方法:目的是隔离复杂度
第一个层面的封装:类就是麻袋,这本身就是一种封装。
第二个层面的封装:类中属性定义私有的,只在类的内部使用,外部无法访问。
第三个层面的封装:明确区分内外,内部的实现逻辑,外部无法知晓,并且为封装到内部的逻辑提供一个访问接口给外部使用。
标签:数据 特定 实现继承 这不 opened 没有 之间 组合 含义
原文地址:https://www.cnblogs.com/wangzhiwei10/p/8976227.html