美文网首页python入门
python第38课练习—类和对象:继承

python第38课练习—类和对象:继承

作者: YoYoYoo | 来源:发表于2019-06-12 12:47 被阅读0次

1、继承机制给程序员带来最明显的好处是?

答:可以偷懒,据说这是每一个优秀程序员的梦想!

  • 如果一个类A继承自另一个类B,就把这个A称为B的子类,把B称为A的父类、基类或超类。继承可以使得子类具有父类的各种属性和方法,而不需要再次编写相同的代码(偷懒)。
  • 在子类继承父类的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类的原有属性和方法,使其获得与父类不同的功能。另外,为子类追加新的属性和方法也是常见做法。

2、如果按以下方式重写魔法方法 __init__,结果会怎样?

class MyClass:
    def __init__(self):
        return 'I love FishC.com!'

答:会报错,因为__init__特殊方法不应当返回除了None以外的任何对象。

>>> myclass = MyClass()
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    myclass = MyClass()
TypeError: __init__() should return None, not 'str'

3、当子类定义了与父类相同名字的属性或方法时,Python是否会自动删除父类的相关属性或方法?

答:不会删除!Python的做法跟其他大部分面向对象编程语言一样,都是将父类属性或方法覆盖,子类对象调用的时候会调用到覆盖后的新属性或方法,但父类的仍然还在,只是子类对象“看不到”。

4、假设已有鸟类的定义,现在我要定义企鹅类继承于鸟类,但我们都知道企鹅是不会飞的,我们应该如何屏蔽父类(鸟类)中飞的方法?

答:覆盖父类方法,例如将函数体内容写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()

5、super函数有什么“超级”的地方?

答:super函数超级之处在于你不需要明确给出任何基类(父类)的名字,它会自动帮你找出所有基类以及对应的方法。由于你不用给出基类的名字,这就意味着你如果需要改变类继承关系,你只要改变class语句里的父类即可,而不必在大量代码中去修改所有被继承的方法。
举个例子

  • A: 没有用super函数
    def __init__(self):
        Fish.__init__(self)
        self.hungry = True
  • B:用了super函数后
    def __init__(self):
        super().__init__()  # 修改父类的时候这里就不用修改了
        self.hungry = True

6、多重继承使用不当会导致重复调用(也叫钻石继承、菱形继承)的问题,请分析以下代码在实际编程中有可能导致什么问题?

class A():
    def __init__(self):
        print('进入A...')
        print('离开A...')

class B(A):
    def __init__(self):
        print('进入B...')
        A.__init__(self)
        print('离开B...')

class C(A):
    def __init__(self):
        print('进入C...')
        A.__init__(self)
        print('离开C...')

class D(B,C):
    def __init__(self):
        print('进入D...')
        B.__init__(self)
        C.__init__(self)
        print('离开D...')

答:多重继承容易导致重复调用问题,下边实例化D类后我们发现A被前后进入两次。
这有什么危害呢?举个例子,假设A的初始化方法里有一个计数器,那这样D一实例化,A的计数器就跑了两次(如果遭遇多个钻石重叠结构重叠还要更多),很明显是不符合程序设置的初衷的(程序应该可控,而不能受到继承关系影响)。

进入D...
进入B...
进入A...
离开A...
离开B...
进入C...
进入A...
离开A...
离开C...
离开D...

为了让大家明白,这里只是举例简单的钻石继承问题,在实际编程中,如果不注意多重继承的使用,会导致比这个复杂N倍的现象,调试起来不是一般的痛苦......所以要尽量避免多重继承。

7、如何解决上一题中出现的问题?

答: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...

练习

1、定义一个点(Point)类和直线(Line)类,使用getLen的方法可以获得直线的长度。

提示:

  • 设点A(x1,y1)、点B(x2,y2),则两点构成的直线长度|AB|=\sqrt{(x1-x2)^2+(y1-y2)^2}
  • Python中计算开根号可以使用math模块中的sqrt函数
  • 直线需有两点构成,因此初始化时需要有两个点(Point)对象作为参数。
    代码清单:
import math

class Point():
    def __init__(self,x=0,y=0):
        self.x = x
        self.y = y

    def getX(self):
        return self.x

    def getY(self):
        return self.y

class Line():
    def __init__(self,p1,p2):
        self.x = p1.getX() - p2.getX()
        self.y = p1.getY() - p2.getY()
        self.len = math.sqrt(self.x*self.x + self.y*self.y)

    def getLen(self):
        return self.len

p1 = Point(1,1)
p2 = Point(4,5)
line = Line(p1,p2)
print(line.getLen())

输出:

5.0

相关文章

网友评论

    本文标题:python第38课练习—类和对象:继承

    本文链接:https://www.haomeiwen.com/subject/ivxkfctx.html