面向对象——继承,派生

1.继承

  • 继承指的是类与类之间的关系,是一种什么“是”什么的关系,继承的功能之一就是用来解决代码重用问题
  • 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可以成为基类或超类,新建的类称为派生类或子类
  • 单继承和多继承
  •  1 class ParentClass1:
     2     pass
     3 class ParentClass2:
     4     pass
     5 class SubClass1(ParentClass1):#单继承
     6     pass
     7 class SubClass2(ParentClass1,ParentClass2):#多继承
     8     pass
     9 
    10 #查看继承
    11 print(SubClass1.__bases__)#(<class '__main__.ParentClass1'>,)
    12 print(SubClass2.__bases__)#(<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
    13 #__bases__与__base__的区别
    14 print(SubClass2.__base__)#<class '__main__.ParentClass1'>,只能查看从左到右继承的第一个子类

2.经典类与新式类

 1 #在python2中,经典类:没有继承object的类,以及它的子类都称为经典类
 2 # class Foo:
 3 #     pass
 4 # class Bar(Foo):
 5 #     pass
 6 #在python2中,新式类:继承object的类,以及它的子类都称为新式类
 7 # class Foo(object):
 8 #     pass
 9 # class Bar(Foo):
10 #     pass
11 
12 #在python3中,都是新式类,一个类没有继承object,默认继承object
13 # class Foo:#默认继承object,
14 #     pass
15 # class Bar(Foo):
16 #     pass
17 # print(Foo.__bases__)#(<class 'object'>,)

3.继承与抽象(先抽象再继承)

  • 抽象:抽取类似或者说比较像的部分,抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
  • 继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构
  • 抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

 

4.继承与重用性

  • 在开发程序的过程中,如果已经定义了类A,又想新建立一个类B,但是类B的大部分内容与类A相同,可以通过继承的方式新建类B,让B继承A,B会“遗传”A的所有属性(数据属性和函数属性),实现代码重用,大大节省编程工作量。
  • 常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就大大缩短了软件开发周期,对大型软件开发来说,意义重大
  •  1 #继承属性查找
     2 class Foo:
     3     def f1(self):
     4         print("form Foo.f1")
     5     def f2(self):
     6         print("form Foo.f2")
     7         self.f1()
     8 class Bar(Foo):
     9     def f1(self):
    10         print("form Bar.f1")
    11 b = Bar()
    12 b.f2()
    13 #form Foo.f2   #显而易见,不用解释
    14 #form Bar.f1  #解释:在运行self.f1()时,其实就是b.f1(),所以按照继承顺序,优先从Bar类中找,而不是就近原则,
    15 # 因此打印的是form Bar.f1
    16 print(Bar.mro())
    17 #[<class '__main__.Bar'>, <class '__main__.Foo'>, <class 'object'>]
    继承属性查找

5.派生

  • 子类可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了
  • 在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值
  •  1 class Riven(Hero):
     2     camp='Noxus'
     3     def __init__(self,nickname,aggressivity,life_value,skin):
     4         Hero.__init__(self,nickname,aggressivity,life_value) #调用父类功能
     5         self.skin=skin #新属性
     6     def attack(self,enemy): #在自己这里定义新的attack,不再使用父类的attack,且不会影响父类
     7         Hero.attack(self,enemy) #调用功能
     8         print('from riven')
     9     def fly(self): #在自己这里定义新的
    10         print('%s is flying' %self.nickname)
    View Code

6.继承的实现原理

  • 对于定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表。
  • 经典类:多继承情况下,在要查找属性不存在时,会按照深度优先的方式查找下去,没有mro()方法
  • 经典类
  • 新式类:多继承情况下,在要查找属性不存在时,会按照广度有限的方式查找下去,可通过mro()方式查询继承顺序
  • 新式类
  •  1 class A(object):
     2     def test(self):
     3         print('from A')
     4     pass
     5 
     6 class B(A):
     7     def test(self):
     8         print('from B')
     9     pass
    10 
    11 class C(A):
    12     def test(self):
    13         print('from C')
    14     pass
    15 
    16 class D(B):
    17     def test(self):
    18         print('from D')
    19     pass
    20 
    21 class E(C):
    22     def test(self):
    23         print('from E')
    24     pass
    25 
    26 class F(D,E):
    27     def test(self):
    28         print('from F')
    29     pass
    30 f1=F()
    31 f1.test()
    32 # print(F.mro())# F > D > B > E > C > A > object
    33 #[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>,
    34 # <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
    35 print(F.__bases__)#(<class '__main__.D'>, <class '__main__.E'>)
    36 
    37 #经典类没有提供mro()方法
    pyt3新式类示例

     

  • 为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。这个MRO列表的构造是通过一个C3线性算法来实现的,只在新式类中有,遵循如下三条准则
    • 子类会先于父类被检查
    • 多个父类会根据它们在列表中的顺序被检查
    • 如果对下一个类存在两个合法的选择,选择第一个父类

7.在子类中调用父类的方法

  • 方式一:指名道姓,即父类名.父类方法(),不依赖于继承
  •  1 #方式一
     2 class Vehicle:#定义交通工具类
     3     country = "China"
     4     def __init__(self,name,speed,load,power):
     5         self.name = name
     6         self.speed = speed
     7         self.load = load
     8         self.power = power
     9     def run(self):
    10         print("开动啦。。。")
    11 class Subway(Vehicle):
    12     def __init__(self,name,speed,load,power,line):
    13         Vehicle.__init__(self,name,speed,load,power)#self一定要传
    14         self.line = line
    15     def run(self):
    16         print('地铁%s号线欢迎您' %self.line)
    17         Vehicle.run(self)#self一定要传
    18 line13 = Subway('中国地铁','180m/s','1000人/箱','',13)
    19 line13.run()
    20 # 地铁13号线欢迎您
    21 # 开动啦。。。
    方式一
  • 方式二:super(),依赖于继承
  •  1 #方式二
     2 class Vehicle:#定义交通工具类
     3     country = "China"
     4     def __init__(self,name,speed,load,power):
     5         self.name = name
     6         self.speed = speed
     7         self.load = load
     8         self.power = power
     9     def run(self):
    10         print("开动啦。。。")
    11 class Subway(Vehicle):
    12     def __init__(self,name,speed,load,power,line):
    13         # super(Subway, self).__init__(name,speed,load,power)
    14         super().__init__(name,speed,load,power)
    15         #super(Subway, self)就相当于实例本身,在python3中super()等于super(Subway, self)
    16         self.line = line
    17     def run(self):
    18         print('地铁%s号线欢迎您' %self.line)
    19         # super(Subway, self).run()
    20         super().run()
    21 line13 = Subway('中国地铁','180m/s','1000人/箱','',13)
    22 line13.run()
    View Code
  • 区别:方式一是跟继承没有关系的,而方式二的super()是依赖于继承的,并且即使没有直接继承关系,super依然会按照mro继续往后查找
  •  1 class A:
     2     def test(self):
     3         super().test()
     4 class B:
     5     def test(self):
     6         print("from B")
     7 class C(A,B):
     8     pass
     9 
    10 c = C()
    11 c.test()#from B
    12 print(C.mro())
    13 # [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>]
    View Code

     

posted @ 2017-12-20 15:10  GraceZen  阅读(254)  评论(0)    收藏  举报