第44个练习是关于继承。
第一个例子讲的是隐式继承,什么是隐式继承呢?简单地说,当A类中存在的特性或方法X,而B类中没有定义,直接从A类中继承得来,这种方式得继承就是隐式继承。
如下面得代码ex44a.py:
class Parent(object):
def implicit(self):
print("PARENT implicit()")
class Child(Parent):
pass
if __name__ == "__main__":
dad = Parent()
son = Child()
dad.implicit()
son.implicit()
在Parent类中定义了一个一个implicit的方法,作用是打印出PARENT implicit()
,而在Child类中,并没有新写任何新的方法和特性,直接继承Parent类中的所有方法和特性,这就是隐式继承。
注意的是,该处的code中,与原文不一致的地方是加了一个if __name__ == "__main__"
, 主要的目的是复习一下前面所学到的内容。在直接运行这段代码的时候,将按照原来的形式输出。而如果采用import模块的方式,则不会打印出任何文字。
输出的结果是:
PARENT implict()
PARENT implict()
第二个例子是在子类中重写父类的方法或特性。有的时候,子类中包含有和父类中同样名字的方法或特性,但是方法或特性的细节并不一样,采用隐式继承就无法实现子类对该方法或特性的需求,此时就需要在子类中重写该方法或特性。
在子类中重写的方法或特性将覆盖掉父类中同名的方法,这就是显式覆盖。
代码如下ex44b.[y所示:
class Parent(object):
def override(self):
print("PARENT override()")
class Child(Parent):
def override(self):
print("CHILD override()")
if __name__ == "__main__":
dad = Parent()
son = Child()
dad.override()
son.override()
代码运行的结果是:
PARENT override()
CHILD override()
在Parent()和Child()中含有相同的方法override,此时虽然Child()是Parent()的子类,但是重写的方法将覆盖掉父类中同样名字的方法,使子类保持有新的方法或特性。
第三点涉及到是否直接采用子类的方法或特性(显示覆盖)还是在运行子类的方法或特性之前,首先运行父类的方法。我猜是有的场合,不能完全忽略掉父类中的方法和特性。这个时候就用到了super()函数。
代码如下面的ex44c.py中所示。
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()")
if __name__ == "__main__":
dad = Parent()
son = Child()
dad.altered()
son.altered()
运行的结果如下:
PARENT altered()
CHILD, BEFORE PARENT altered()
PARENT altered()
CHILD, AFTER PARENT altered()
第一个PARENT altered()
比较好理解,这是直接调用父类Parent(object)中的alter方法得到的。
结果第二行中的CHILD, BEFORE PARENT altered()
是第二个例子中的显示覆盖得到的结果。
真正有意思的是结果的第三行和第四行,这两行的结果是由super(Child,self).altered()
运行得到的结果。对于显式覆盖,重写的altered()
方法被直接调用,不用再管其继承的父类中的信息。而用super(Child,self).alter()
,将会去访问其父类,并返回父类中的alter()
方法。
可以想想采用这种继承的方式,在实际编程的时候有什么用处,现在mark一下,因为我也没有合适的例子。总之,如书中所讲,这种方式,可以在父类方法/特性运行后再用子类的方法/特性进行替换。
下面是三种方式组合使用的代码ex44d.py.
class Parent(object):
def override(self):
print("PARENT override()")
def altered(self):
print("PARENT altered()")
def implicit(self):
print("PARENT implicit()")
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()
运行的结果如下:
PARENT implicit()
PARENT implicit()
PARENT override()
CHILD override()
PARENT altered()
CHILD, BEFORE PARENT altered()
PARENT altered()
CHILD, AFTER PARENT altered()
到了这里,就要问一句:super()函数的意义在什么地方?因为隐式继承和显式覆盖这两种方式可以保证对父类中方法/特性的继承和重写,看起来功能都是足够了。但考虑到多重继承的情况,实际的情况可能相当复杂,例如当某个子类继承了多个父类,Child(P1,P2,P3,…),而这些父类之间可能有相同的方法/特性,或它们之间也有继承的关系,这样的继承关系就相当的复杂。在super机制里可以保证公共父类仅被执行一次,至于执行的顺序,是按照MRO(Method Resolution Order):方法解析顺序 进行的。
重点标记:
-super()最常见的用法是在父类的__init__
函数中使用。通常这也是唯一可以进行这种操作的地方。
-可以直接使用别的类和模块,而非依赖于隐式继承。
-不惜一切代价去避免多重继承。
-需要代码复用的地方,可以通过组合做成模块。