第038讲:类和对象:继承 课后测试题及答案
课堂笔记
如果子类中定义与父类同名的方法或属性,则会自动覆盖父类对应的方法或属性:
演示 覆盖代码:
1 import random as r 2 3 class Fish: 4 def __init__(self): 5 self.x = r.randint(0, 10) 6 self.y = r.randint(0, 10) 7 8 def move(self): 9 self.x -= 1 10 print('我的位置是:', self.x, self.y) 11 12 13 class Goldfish(Fish): 14 pass 15 16 class Carp(Fish): 17 pass 18 19 class Salmon(Fish): 20 pass 21 22 class Shark(Fish): 23 def __init__(self): 24 self.hungry = True 25 26 def eat(self): 27 if self.hungry: 28 print('吃货的梦想就是天天有得吃^_^') 29 self.hungry = False 30 else: 31 print('吃不下了')
子类重写了父类的方法,所以鲨鱼不能移动。
使用这种技术有2中方法:
1、调用未绑定的父类方法
2、使用super函数
第一种:
第二种,使用super函数
super函数的超级之处就在于你不用给定鸡肋的名字,如果继承有多重继承的话,或者说一路继承有好多个祖先类,你不用去给出任何的名字,它会帮你一层层的找出对应的方法;由于你不用给出鸡肋的名字,意味着你需要改变继承的类只需在括号内改变父类就可。
多重继承
很简单,就是继承的父类多写几个。
多重很牛B,但是很容易代码混乱。
课后测试题及答案
测试题:
0. 继承机制给程序猿带来最明显的好处是?
不用重复的写一些代码,在创建好一个类后,对于想新建一个类。但是新建的类的功能是在某个类基础之上的,使用继承机制,可以节省时间与代码量,提高效率
答:可以偷懒,据说这是每一个优秀程序猿的梦想!
如果一个类 A 继承自另一个类 B,就把这个 A 称为 B 的子类,把 B 称为 A 的父类、基类或超类。继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码(偷懒)。
在子类继承父类的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类的原有属性和方法,使其获得与父类不同的功能。另外,为子类追加新的属性和方法也是常见的做法。
1. 如果按以下方式重写魔法方法 __init__,结果会怎样?
class MyClass: def __init__(self): return "I love FishC.com!"
初始化就会返回语句
实验了,会报错,这个初始化应该返回None,而不是一个字符串
答:会报错,因为 __init__ 特殊方法不应当返回除了 None 以外的任何对象。
>>> myClass = MyClass() Traceback (most recent call last): File "<pyshell#13>", line 1, in <module> myClass = MyClass() TypeError: __init__() should return None, not 'str'
2. 当子类定义了与相同名字的属性或方法时,Python 是否会自动删除父类的相关属性或方法?
会覆盖掉父类的相关属性和方法,解决的话有2中办法,一种是在子类中调用未绑定的父类方法;一种是使用super函数。
答:不会删除!Python 的做法跟其他大部分面向对象编程语言一样,都是将父类属性或方法覆盖,子类对象调用的时候会调用到覆盖后的新属性或方法,但父类的仍然还在,只是子类对象“看不到”。
3. 假设已经有鸟类的定义,现在我要定义企鹅类继承于鸟类,但我们都知道企鹅是不会飞的,我们应该如何屏蔽父类(鸟类)中飞的方法?
如何屏蔽。。。肯定不能使用创新定义相同名字来覆盖吧
答:覆盖父类方法,例如将函数体内容写 pass,这样调用 fly 方法就没有任何反应了。
class Bird: def fly(self): print("Fly away!") class Penguin(Bird): def fly(self): pass >>> bird = Bird() >>> penguin = Penguin() >>> bird.fly() Fly away! >>> penguin.fly()
4. super 函数有什么“超级”的地方?
它不用关系任何基肋的父类名字等,只有调用super().xx方法() 不需要加self,就可以自己找到定义子类时括号内填的父类,非常人性化~
答:super 函数超级之处在于你不需要明确给出任何基类的名字,它会自动帮您找出所有基类以及对应的方法。由于你不用给出基类的名字,这就意味着你如果需要改变了类继承关系,你只要改变 class 语句里的父类即可,而不必在大量代码中去修改所有被继承的方法。
5. 多重继承使用不当会导致重复调用(也叫钻石继承、菱形继承)的问题,请分析以下代码在实际编程中有可能导致什么问题?
1 class A(): 2 def __init__(self): 3 print("进入A…") 4 print("离开A…") 5 6 class B(A): 7 def __init__(self): 8 print("进入B…") 9 A.__init__(self) 10 print("离开B…") 11 12 class C(A): 13 def __init__(self): 14 print("进入C…") 15 A.__init__(self) 16 print("离开C…") 17 18 class D(B, C): 19 def __init__(self): 20 print("进入D…") 21 B.__init__(self) 22 C.__init__(self) 23 print("离开D…")
答:多重继承容易导致重复调用问题,下边实例化 D 类后我们发现 A 被前后进入了两次(有童鞋说两次就两次憋,我女朋友还不止呢……)。
这有什么危害?我举个例子,假设 A 的初始化方法里有一个计数器,那这样 D 一实例化,A 的计数器就跑两次(如果遭遇多个钻石结构重叠还要更多),很明显是不符合程序设计的初衷的(程序应该可控,而不能受到继承关系影响)。
>>> d = D()
进入D…
进入B…
进入A…
离开A…
离开B…
进入C…
进入A…
离开A…
离开C…
离开D…
为了让大家都明白,这里只是举例最简单的钻石继承问题,在实际编程中,如果不注意多重继承的使用,会导致比这个复杂N倍的现象,调试起来不是一般的痛苦……所以一定要尽量避免使用多重继承。
想更多的了解,阅读 -> 多重继承的陷阱:钻石继承(菱形继承)问题
6. 如何解决上一题中出现的问题?
答:super 函数再次大显神威。
class A(): def __init__(self): print("进入A…") print("离开A…") class B(A): def __init__(self): print("进入B…") super().__init__() print("离开B…") class C(A): def __init__(self): print("进入C…") super().__init__() print("离开C…") class D(B, C): def __init__(self): print("进入D…") super().__init__() print("离开D…") >>> d = D() 进入D… 进入B… 进入C… 进入A… 离开A… 离开C… 离开B… 离开D…
动动手:
0. 定义一个点(Point)类和直线(Line)类,使用 getLen 方法可以获得直线的长度。
提示:
设点 A(X1,Y1)、点 B(X2,Y2),则两点构成的直线长度 |AB| = √((x1-x2)2+(y1-y2)2)
Python 中计算开根号可使用 math 模块中的 sqrt 函数
直线需有两点构成,因此初始化时需有两个点(Point)对象作为参数
写到这不会了,怎么在Line类中初始化的时候就有两个点啊。。。
答案:
1 import math 2 3 class Point(): 4 def __init__(self, x=0, y=0): 5 self.x = x 6 self.y = y 7 8 def getX(self): 9 return self.x 10 11 def getY(self): 12 return self.y 13 14 class Line(): 15 def __init__(self, p1, p2): 16 self.x = p1.getX() - p2.getX() 17 self.y = p1.getY() - p2.getY() 18 self.len = math.sqrt(self.x*self.x + self.y*self.y) 19 20 def getLen(self): 21 return self.len 22 23 >>> p1 = Point(1, 1) 24 >>> p2 = Point(4, 5) 25 >>> line = Line(p1, p2) 26 >>> line.getLen() 27 5.0
作者:Agiroy_70
本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。
博主的文章主要是记录一些学习笔记、作业等。文章来源也已表明,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。
博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!