继承与复用
在自定义类型的基本形式中:
class ClassName(ParentClass):
"""class docstring"""
def some_method(self, ...):
return ...
ParentClass是用来进行继承的,被继承的ParentClass是父类,定义的ClassName是子类。可以认为子类是一种特殊的父类。
例如,假设父类是哺乳动物,人作为一个子类可以继承这个父类,因为人是哺乳动物的一种;狮子也可以继承哺乳动物,因为狮子也是哺乳动物的一种。
类的继承
考虑这样一个表示树叶的类:
class Leaf(object):
def __init__(self, color='green'):
self.color = color
def fall(self, season="autumn"):
print(f"A leaf falls in {season}!")
继承这个类,生成一个枫树叶类:
class MapleLeaf(Leaf):
def change_color(self):
if self.color == "green":
self.color = "red"
构造一个子类对象:
mleaf = MapleLeaf()
子类会继承父类的属性和方法,父类的属性和方法可以直接调用:
mleaf.fall()
A leaf falls in autumn!
mleaf.color
'green'
子类虽然没有定义构造函数,但是会直接继承父类的构造函数:
mleaf2 = MapleLeaf("orange")
mleaf2.color
'orange'
子类额外定义的方法:
mleaf.change_color()
mleaf.color
'red'
方法的重载
子类可以对父类中已有的方法进行重载。例如,在枫树叶类中对.fall()
方法进行重载,即重新定义:
class MapleLeaf(Leaf):
def change_color(self):
if self.color == "green":
self.color = "red"
def fall(self, season="autumn"):
self.change_color()
print(f"A leaf falls in {season}!")
在这个例子中,.fall()
方法被重载,并调用了自定义类中的已有方法。方法定义中的第一个参数self
表示的就是对象自身,所以可以用self.change_color()
实现对已有方法的调用:
mleaf = MapleLeaf()
mleaf.color
'green'
mleaf.fall()
A leaf falls in autumn!
mleaf.color
'red'
super()函数
与父类的.fall()方法相比,子类的方法只增加了.change_color()的调用,之后的操作与父类的.fall()方法一致,代码其实有冗余和浪费。Python提供了super()
函数,在子类中调用父类的方法。具体定义如下:
class MapleLeaf(Leaf):
def change_color(self):
if self.color == "green":
self.color = "red"
def fall(self, season="autumn"):
self.change_color()
super(MapleLeaf, self).fall(season)
# print(f"A leaf falls in {season}!")
能实现与上面一样的结果:
mleaf = MapleLeaf()
mleaf.color
'green'
mleaf.fall()
A leaf falls in autumn!
mleaf.color
'red'
鸭子类型:一切都是为了复用
鸭子类型(Duck Type)的概念来源于美国诗人詹姆斯·惠特科姆·莱利的诗句:“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”在Python中,这个概念被衍生为:在使用对象时,可以不关注对象的类型,而关注对象具有的方法或属性;只要对象的属性和方法满足条件,就认为该对象是合法的。
例如,定义这样的一个函数:
def something_fall(leaf):
leaf.fall()
这个函数接受一个参数leaf,并调用它的.fall()方法。Leaf类支持.fall()方法,因此该类型的对象是合法的:
leaf = Leaf()
something_fall(leaf)
A leaf falls in autumn!
子类MapleLeaf也支持.fall()方法,所以也是合法的对象:
mleaf = MapleLeaf()
something_fall(mleaf)
A leaf falls in autumn!
再定义一个类苹果:
class Apple(object):
def fall(self):
print("An apple falls!")
apple = Apple()
something_fall(apple)
An apple falls!
在鸭子类型机制下,Python将函数和方法中的类型检查,变成了接口检查的模式,即something_fall()函数不会检查传入的参数leaf是什么类型,而是检查leaf有没有实现.fall()接口。