• 第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

    本博客所有文章仅用于学习、研究和交流目的,欢迎非商业性质转载。

    博主的文章主要是记录一些学习笔记、作业等。文章来源也已表明,由于博主的水平不高,不足和错误之处在所难免,希望大家能够批评指出。

    博主是利用读书、参考、引用、抄袭、复制和粘贴等多种方式打造成自己的文章,请原谅博主成为一个无耻的文档搬运工!

  • 相关阅读:
    关键词学英语----设计模式
    nginx配置
    文件File类型接收
    md工具
    springboot集成Spring Data JPA
    maven应用
    2019年Java面试题基础系列228道(3)
    2019年Java面试题基础系列228道(2)
    2019年Java面试题基础系列228道(1)
    天空盒
  • 原文地址:https://www.cnblogs.com/hale547/p/13353752.html
Copyright © 2020-2023  润新知