四、类的继承
面向对象的最大优点之一就是可以通过继承来减少代码,同时灵活地定制新类。
1.类的继承
子类继承父类后,就有了父类的属性和方法,除了父类的私有属性和私有方法(属性名或方法名前面有两个下划线 "__"
的),子类中还可以通过重载来修改父类的方法,以实现与父类不同的行为或表现能力。
例六:
class Ant:
def __init__(self, x=0, y=0,color='black'): #定义构造方法
self.x = x
self.y = y
self.color = color
def crawl(self, x, y): #定义方法,模拟爬行
self.x = x
self.y = y
print('爬行...')
self.info()
def info(self):
print('当前位置:(%d, %d)'%(self.x, self.y))
def attack(self): #定义方法,模拟攻击
print('用嘴咬!')
class FlyAnt(Ant): #定义子类,继承def的父类是Ant类
def attack(self): #重新定义了函数attack(),这叫函数重载
print('用尾针!')
def fly(self, x, y): #定义新方法(模拟飞行)
print('飞行...')
self.x = x
self.y = y
self.info()
flyant = FlyAnt(color='red') #实例化子类,
flyant.crawl(3, 5)
flyant.fly(10, 14)
flyant.attack()
输出:
爬行...
当前位置:(3, 5)
飞行...
当前位置:(10, 14)
用尾针!
代码说明:
程序一开始定义了父类Ant
,具有爬行、用嘴咬的能力,之后定义了子类FlyAnt
,子类继承了父类爬行的能力,修改了攻击方式,新增了飞行能力。之后实例化调用其爬行、飞行、进攻方式。
2.多重继承
在面向对象编程的语言中,有的允许多重继承,即一个类可以继承多个类,有的只允许单一继承;python则允许多重继承。
多重继承的形式:
class <子类名>(父类名1, 父类名2, ...):
pass
多重继承的继承顺序很重要,如果继承的父类有多个相同的方法名(包括构造方法),但在类中使用时未指定父名,则python从左到右搜索,即调用先继承的类中的同名的方法。
例七:
先定义类:
class A: #定义类A
def info(self):
print('A')
class B: #定义类B
def info(self):
print('B')
class C1(A, B): #定义子类C1
pass
class C2(B, A): #定义子类C2
pass
class C3(A, B): #定义子类C3
def info(self):
A.info(self)
B.info(self)
实例化:
c_1 = C1()
c_1.info()
print('**************************')
c_2 = C2()
c_2.info()
print('**************************')
c_3 = C3()
c_3.info()
输出:
A
**************************
B
**************************
A
B
代码分析:
-
这个程序先定义了A、B两个类,然后定义了三个子类,子类C1先继承A再继承B,由于A、B两个类有相同的方法
info()
,所以按照继承先后顺序,C1继承了A的方法,而C2则相反。 -
对于C3,C3定义重新定义(即重载)了方法
info()
,然后分别调用了A、B类的方法(A.info(self)、B.info(self)
),因为它调用时指明了父名 A、B,所以它两个父类的方法都继承了。
3.方法重载
上面已经多次提到过函数重载,这里再详细说下。
-
当子类继承父类时,子类如果要想修改父类的行为,则应使用方法重载来实现。
-
方法重载的基本方式:在子类中定义一个与所继承的父类中要重载方法的名字一样的方法。(即定义的方法名要与被重载的方法的名字一样)
-
在例六中,子类
FlyAnt
继承了父类Ant
,父类中已经定义了方法attack()
,而子类中也定义了一个attack()方法,即attack()方法被重载了。当子类实例调用attack()方法时,就会直接调用子类中的attack)方法,而不会调用父类中同名的方法。
-
再如在实例七的多重继承中,两个父类都具有同名方法
info()
,但在子类C3
中也定义了个 info()方法,即info()方法被重载了。当子类实例
c_3
调用info()方法时,就会直接调用该实例中定义的info()方法,而不会去调用任何一个父类的info()方法。