习题44 继承与合成

牢记一句话:大部分使用继承的场合都可以用合成代替,而多重继承则需要不惜一切地避免之。


有三种继承如下:

  • 隐式继承

当你在父类里定义了一个函数但没有在子类中定义的例子时,会发生隐式继承。

class Parent(object):

    def implicit(self):
        print "PARENT implicit()"

class Child(Parent):
    pass

dad = Parent()
son = Child()

dad.implicit()
son.implicit()

class Child:中的 pass 是在Python中创建空代码块的方法。这样就创建了一个叫 Child 的类,但是没有在里面定义任何细节。在这里它会从它的父类继承所有的行为。

运行如下:


将函数放到基类(Parent)中,那么所有的子类(Child)将会自动获得这些函数功能。

需要很多类的时候,可以避免重复写很多代码。

  • 显式覆盖

有时候要让子类的函数有一个不同的行为,这样情况隐式继承做不到。需要覆盖子类的函数才行。

例子如下:

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()  


这里两个类里面都定义了一个函数,叫做 override ,但是运行结果如下

可以发现子类中新定义的函数 override 取代了父类里面的 override。


  • 在运行前或者运行后替换

使用继承的第三种方法是一个覆盖的特例,这种情况下,你想在父类中定义的内容运行前或者之后再修改行为。

首先要像上个例子一样覆盖函数,然后要接着用 Python 的内置函数 super 来调用父类 Parent 里面的版本。

例子如下:

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,AFTER PARENT altered()"  
  
dad = Parent()  
son = Child()  
  
dad.altered()  
son.altered()


运行结果如下:



最重要的是其中的9-11行,当调用 son.altered() 的时候,完成了以下内容:

1.由于覆盖了 Parent.altered ,实际运行的是 Child.altered,所以第9行的输出是意料之中。


2.这里想要在前后加一个动作,所以第9行以后要用 super 来获取 Parent.altered 这个版本。


3.第10行调用了 super(Child, self).altered() ,这和过去用过的 getattr 很相似,不过它还知道你的继承关系,并且会访问到Parent 类。这句话你可以读作 :“用 Child 和 Self 这两个参数调用 super,然后在此返回的基础上调用 altered。”


4.到这里 Parent.altered 就会被运行,然后打印出父类的信息。


5.最后从 Parent.altered 返回到 Child.altered ,打印出后面的信息。


  • 三种方式组合使用

演示一个最终版本,在一个文件中演示三种交互:

#-*-coding:utf-8-*-   
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() # 执行 Parent 类里面的 implicit ,打印"PARENT implicit()" 
son.implicit() # Child 里面没有定义 implicit ,从 Parent 里面继承

dad.override() # 执行 Parent 类里面的 override ,打印"PARENT override()"
son.override() # Child 里面有 override ,打印"CHILD override()"

dad.altered() # 执行 Parent 类里面的altered ,打印"PARENT altered()"
son.altered() # Child 里面有 altered 打印"CHILD, BEFORE PARENT altered()"
              # 然后用 Child 和 self 这两个参数调用 super ,在此返回的基础上调用 altered ,这里
              # Parent.altered 就会被运行,打印出了"PARENT altered()"
              # 最后打印"CHILD,AFTER PARENT altered()"


附加了足够的注释,运行结果如下:
习题44 继承与合成_第1张图片


======================================================================================================

为什么要用 super() 

        这里要讲到“多重继承”。多重继承指的是定义的类继承了多个类。比如:

class SuperFun(Child, BadStuff):
    pass
这相当于说“创建一个叫 SuperFun 的类,让它同时继承Child 和 BadStuff”。

具体原理没啥意思好像,反正我也用不到。可以看书,这里不写了。

super() 和 __init__搭配使用

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

class Child(Parent):

    def __init__(self, stuff):
        self.stuff = stuff
        super(Child, self).__init__()
这里和上面的 Child.altered 差别不大,只不过在 __init__  里面先设置了一个变量,然后才用 Parent.__init__ 初始化了 Parent。


======================================================================================================

合成

        继承是一种有用的技术,不过还有一种实现相同功能的方法,就是直接使用别的类和模块,而非依赖于继承。回头来看,前面说了三种继承方式,有两种会通过新代码取代或者修改父类的功能。这其实可以很容易用调用模块里面的函数来实现。

class Other(object):

    def override(self):
        print "OTHER override()"

    def implicit(self):
        print "OTHER implicit()"

    def altered(self):
        print "OTHER implicit()"

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() # print "OTHER implicit()"
son.override() # print "CHILD override()"
son.altered() # print "CHILD, BEFORE OTHER altered()"
           # print "OTHER implicit()"
           # print "CHILD, AFTER OTHER altered()"

这里没有使用 Parent 这样的名称,因为这里不是父类子类的“A是B”的关系,而是一个“A里有B”的关系,这里 Child 里有一个 Other 用来完成它的功能。运行的时候,我们可以看见这样的输出:

习题44 继承与合成_第2张图片

Child 和 Other 里面大部分一样,唯一不同的是,必须定义一个 Child.implicit 函数来完成它的功能。


======================================================================================================

继承和合成的应用场合

指导方法:

1.不惜一切代价避免多重继承,因为它带来的麻烦比能解决的问题都多。

    如果非要用,那得准备好钻研类的层次结构,以及花时间去找各种东西的来龙去脉。

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

3.只有在代码之间有清楚的关联,可以通过一个单独的共性联系起来的时候使用继承,或者受现有代码或者别的不可抗拒因素      非用不可,那也用吧。

然而,不要成为这些规则的奴隶。




你可能感兴趣的:(新手入门)