习题36:类的继承和合成

发布时间:2017-12-02 16:01:26编辑:Run阅读(5991)

    什么是继承?

    继承的用处,就是用来指明一个类的大部分或全部功能,都是从一个父类中获得的,当你写成class Foo(Bar)时,代码就发生了继承效果,这句代码的意思是“创建一个叫Foo的类,并让他继承Bar”,当你这样写时,python语言会让Bar的实例具有的功能都工作在Foo的实例上,这样可以让你把通用的功能放到Bar里边,然后在给Foo特别设定一些功能


    隐式继承

    首先在父类里定义了一个函数,但没有在子类中定义的例子,这时候会发生隐式继承

    代码如下

    # coding: utf-8
    __author__ = 'www.py3study.com'
    class Parent(object):
       def implicit(self):
           print("PARENT implicit")

    class Child(Parent):
       pass

    dad = Parent()
    son = Child()
    dad.implicit()
    son.implicit()

    应该看到的结果

    图片.png

    class Child:中的pass是在python中创建空的代码区块方法,这样就创建了一个叫Child的类,但没有在里边定义任何细节,在这里它会从它的父类中继承所有的行为,运行起来就是这样(上图)

    这就说明,如果你将函数放到基类中(也就是这里的Parent),那么所有的子类(也就是Child这样的类)将会自动获得这些函数功能。如果你需要很多类的时候,这样可以让你避免重复写很多代码


    显示覆写(Explicit Override)

    有时候你需要让子类里的函数有一个不同的行为,这种情况下隐式继承是做不到的,而你需要覆写子类中的函数,从而现实它的新功能,你只要在子类Child中定义一个相同名称的函数就可以了

    代码如下:

     # coding: utf-8
    __author__ = 'www.py3study.com'
    class Parent(object):
       def override(self):
           print("PARENT override()")

    class Child(Parent):
       def override(self):
           print("CHILD override()")

    dad = Parent()
    son = Child()
    dad.override()
    son.override()

    应该看到的结果

    图片.png

    如你所见,子类中新定义的函数在这里取代了父类的函数(也就是覆写)


    在运行前或运行后覆写

    第三种继承的方法是一个覆写的特例,这种情况下,你想在父类中定义的内容运行之前或者之后再修改的行为。首先你像上例一样覆写函数,不过接着你用python的内置函数super来调用父类Parent里的版本

    代码如下

    # coding: utf-8
    __author__ = 'www.py3study.com'
    class Parent(object):
       def altered(self):
           print("PARENT altered()")

    class Child(Parent):
       def altered(self):
           print("CHILD, BEFORE PARENT altered()")
           super(Child, self).altered()
           print("CHILD,改写了")

    dad = Parent()
    son = Child()
    dad.altered()
    son.altered()

    应该看到的结果

    图片.png

    super(Child, self).altered()  调用super并且加上Child和self这两个参数,在此返回的基础上然后调用alterrd.

    super这种方法会知道你继承的关系,所以结果就是执行了父类的altered函数里面的print("PARENT altered()")

    一起使用三种方式代码如下:

    # coding: utf-8
    __author__ = 'www.py3study.com'
    class Parent(object):
        def override(self):
            print("PARENT override()")
    
        def implicit(self):
            print("PARENT implicit()")
    
        def altered(self):
            print("PARENT altered()")
    
    class Child(Parent):
        def override(self):
            print("CHILD override()")
    
        def altered(self):
            print("CHILD, BEFORE PARENT altered()")
            super(Child, self).altered()
            print("CHILD, AFTER PARENT altered()")
    
    dad = Parent()
    son = Child()
    dad.implicit()
    son.implicit()
    dad.override()
    son.override()
    dad.altered()
    son.altered()

    应该看到的结果

    图片.png

    为什么要用super()

    多重继承(Multiple Inheritance)的麻烦东西,多重继承是指你定义的类继承了多个类,就像这样

    class SuperFun(Child, BadStuff):

        pass

    这相当于说"创建了一个叫SuperFun的类,让它同时继承Child和BadStuff"

    Super()这个函数,就是应用这种场合,使用Super()函数python会自己找到正确的函数


    super()和__init__搭配使用

    最常见的super()的用法是在基类的__init__函数中使用,通常这也是唯一可以进行这种操作的地方,在这里你在子类里做了一些事情,然后完成对父类的初始化,示例代码如下

    class Child(Parent):

        def __init__(self, stuff):

            self.stuff = stuff

            super(Child, self).__init__()

    这和上面的Child.altered差别不大,只不过在__init__里边先设了个变量,然后才用Parent.__init__初始化了Parent


    合成

    继承是一种有用的技术,不过还有一种实现相同功能的方法,就是直接使用别的类和模块,而非依赖于继承

    示例代码如下

    # coding: utf-8
    __author__ = 'www.py3study.com'
    class Other(object):
        def override(self):
            print("OTHER override()")
    
        def implicit(self):
            print("OTHER implicit()")
    
        def altered(self):
            print("OTHER altered()")
    
    class Child(object):
        def __init__(self):
            self.other = Other()
    
        def implicit(self):
            self.other.implicit()
    
        def override(self):
            print("CHILD override()")
    
        def altered(self):
            print("CHILD, BEFORE OTHER altered()")
            self.other.altered()
            print("CHILD, AFTER OTHER altered()")
    
    son = Child()
    son.implicit()
    son.override()
    son.altered()

    应该看到的结果

    图片.png

    这里没有使用Parent这个名称,因为这里不是父类子类的"A是B"的关系,而是一个"A里有B"的关系,这里Child里有一个Other用来完成它的功能


    继承和合成的应用场合

    “继承vs合成”的问题说到底还是关于代码重用的问题,你不想到处都是重复的代码,这样既难看又没效率。继承可以让你在基类里隐含父类的功能,从而解决了这个问题。而合成则是利用模块和别的类中的函数调用实现了相同的目地

    如果两种方案都能解决重用的问题,那什么时候该用哪个呢?这个问题的答案其实是非常主观的,推荐三个大体的指引方案

    1 不惜一切代价地避免多重继承,它带来的麻烦比能解决的问题都多,如果你非要用,拿你得准备好专研类的层次结构,以及花时间去找各种东西的来龙去脉

    2 如果你有一些代码会在不同位置和场合应用到,那就用合成来把它们做成模块

    3 只有在代码之间有清楚的关联,可以通过一个单独的共性联系起来的时候使用继承


    常见问题

    怎么样增强自己解决新问题的技术?

    提高解决问题能力的唯一方法就是自己去努力解决尽可能多的问题,很多时候人们碰到难题就会跑去找人给出答案,当你没时间需要尽快解决的时候,这样做是没有问题的,但是如果时间足够,那就花时间自己解决吧

    对象是不是就是类的拷贝?

    有的语言里是这样的,例如javascript,这样的语言叫做prototype语言,这种语言里的类和对象除了用法以外没多少不同。不过在python里类其实像是用来创建对象的模版,就跟制作硬币用到的模具一样


关键字