1. 定义
即把子类中大家都要用的相同的方法和属性
,统一定义到父类当中(子类各自不同的方法仍定义在自己的类中),然后子类在用到这些方法的时候,可以通过类指针到父类当中进行查找并使用,这就是继承
如,A类和B类均需要调用某些相同的属性和方法,那么我们此时创建C类,将这些相同的方法写到C类中;然后A、B类分别继承C类,此时,A的对象和B的对象均可以直接调用C类中的方法
class C:
'''
定义了A类和B类均需要调用的属性和方法
'''
pass
class A(C): # A类继承C类
pass
class B(C): # B类继承C类
pass
2. 用法
我们引用《面向对象 方法定义与调用》中人狗大战的例子来进行类的继承的说明
原例如下:
class Person:
def __init__(self,name,job,hp,ad):
self.username = name
self.userjob = job
self.userhp = hp
self.userad = ad
def attack(self,dog):
dog.hp -= self.userad
print('%s攻击了%s,%s掉了%s点血' % (self.username,dog.name,dog.name,self.userad))
class Dog:
def __init__(self,name,kind,hp,ad):
self.name = name
self.kind = kind
self.hp = hp
self.ad = ad
def beat(self,person):
person.hp -= self.ad
print('%s咬了%s,%s掉了%s点血' % (self.name,person.username,person.username,self.ad))
tom = Person('tom','法师',1000,50)
maomao = Dog('maomao','泰迪',500,10)
tom.attack(maomao)
print('maomao当前血量为:',maomao.hp)
'''输出'''
# tom攻击了maomao,maomao掉了50点血
# maomao当前血量为: 450
2.1 方法的继承
我们在上例的基础上,给Person和Dog类均加一个吃药恢复血量的方法
,由于这个方法是共有的,因此我们可以将这个方法写到一个统一的类中,再由Person类和Dog类去继承即可获取该方法
代码示例如下:
class Animal:
def eat(self):
self.hp += 10
class Person(Animal):
def __init__(self,name,job,hp,ad):
self.name = name
self.job = job
self.hp = hp
self.ad = ad
def attack(self,dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.name,dog.name,dog.name,self.ad))
class Dog(Animal):
def __init__(self,name,kind,hp,ad):
self.name = name
self.kind = kind
self.hp = hp
self.ad = ad
def beat(self,person):
person.userhp -= self.ad
print('%s咬了%s,%s掉了%s点血' % (self.name,person.name,person.name,self.ad))
tom = Person('tom','法师',1000,50)
maomao = Dog('maomao','泰迪',500,10)
tom.attack(maomao)
print('maomao当前血量为:',maomao.hp)
maomao.eat()
print('maomao吃药后血量为:',maomao.hp)
'''输出'''
# tom攻击了maomao,maomao掉了50点血
# maomao当前血量为: 450
# maomao吃药后血量为: 460
由上述代码可以看出,Person和Dog类均继承Animal(父类)类,也就是Person和Dog类实例化后的对象均可调用Animal类中定义的eat
方法。从上述代码可以看出,maomao在调用eat方法后,血量成功上升了10点
继承逻辑说明图:
子类的命名空间中会有类指针
指向其父类的命名空间(即地址)
如上,以代码中实例化后的对象maomao调用eat方法为例说明:
1)maomao调用eat方法,会通过对象指针
到Dog类中找eat方法
2)当maomao在Dog类中未找到eat方法,然后Dog子类会通过类指针
到其父类(Animal类)中找eat方法
3)找到eat方法后即可调用
注:若maomao在Dog类中就找到了eat方法,则不会再去Dog的父类中去找
2.2 属性的继承
一旦子类的实例在子类中找到了init方法,就不再往子类的父类中去找init方法了,需要手动在子类的init方法中调用一下父类的init方法,并传入父类init方法所需要的参数
1)当未在子类中调用父类的init方法
代码示例
class Animal:
def __init__(self,name,hp,ad):
print('我被调用了') # 判断父类的init方法是否被调用
self.name = name
self.hp = hp
self.ad = ad
def eat(self):
self.hp += 10
class Person(Animal):
def __init__(self,name,job,hp,ad):
self.job = job # 人特有属性
def attack(self,dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.name,dog.name,dog.name,self.ad))
class Dog(Animal):
def __init__(self,name,kind,hp,ad):
self.kind = kind # 狗特有属性
def beat(self,person):
person.hp -= self.ad
print('%s咬了%s,%s掉了%s点血' % (self.name,person.name,person.name,self.ad))
tom = Person('tom','法师',1000,50)
print('tom_dict',tom.__dict__) # 查看tom拥有的属性
maomao = Dog('maomao','泰迪',500,10)
print('maomao_dict',maomao.__dict__) # 查看maomao用用的属性
tom.attack(maomao)
print('maomao当前血量为:',maomao.hp)
maomao.eat()
print('maomao吃药后血量为:',maomao.hp)
maomao.beat(tom)
print('tom当前血量:',tom.hp)
执行报错结果
tom_dict {'job': '法师'}
Traceback (most recent call last):
maomao_dict {'kind': '泰迪'}
File "/Users/malingang/Knowledge/Python/Pycharm_Project/Py27/classes/day07/practice/面向对象博客/继承2.py", line 34, in <module>
tom.attack(maomao)
File "/Users/malingang/Knowledge/Python/Pycharm_Project/Py27/classes/day07/practice/面向对象博客/继承2.py", line 16, in attack
dog.hp -= self.ad
AttributeError: 'Dog' object has no attribute 'hp'
由上述报错结果可以看出:
Animal类中的init并未被调用,所以,当前tom和maomao实际上仅有其子类(person和dog类)自身当属性,而没有继承他们父类Animal的属性
父类init方法未被调用的原因:一旦实例在子类中找到了init方法,就不再往子类的父类中去找init方法了
如何能成功调用父类中的init方法:
方法1:删除掉子类中的init方法,实例在子类中找不到init方法,就会去其父类找(若子类有自身单独的属性,则此方法不适合;如狗的kind属性和人的job属性)
方法2:在子类的init方法中调用一下父类的init方法
2)在子类中调用父类的init方法
需要在子类的init方法当中调用父类的init方法,才能保证子类实例化后的对象于子类中找到init方法之后,仍然会去调用父类中的init方法中定义的属性
代码示例
class Animal:
def __init__(self,name,hp,ad):
print('我被调用了') # 判断父类的init方法是否被调用
self.name = name
self.hp = hp
self.ad = ad
def eat(self):
self.hp += 10
class Person(Animal):
def __init__(self,name,job,hp,ad):
self.job = job # 人特有属性
Animal.__init__(self,name,hp,ad) # # 调用Animal类的init方法;注意要传入self参数
def attack(self,dog):
dog.hp -= self.ad
print('%s攻击了%s,%s掉了%s点血' % (self.name,dog.name,dog.name,self.ad))
class Dog(Animal):
def __init__(self,name,kind,hp,ad):
self.kind = kind # 狗特有属性
Animal.__init__(self,name,hp,ad) # 调用Animal类的init方法;注意要传入self参数
def beat(self,person):
person.hp -= self.ad
print('%s咬了%s,%s掉了%s点血' % (self.name,person.name,person.name,self.ad))
tom = Person('tom','法师',1000,50)
print('tom_dict',tom.__dict__) # 查看tom拥有的属性
maomao = Dog('maomao','泰迪',500,10)
print('maomao_dict',maomao.__dict__) # 查看maomao用用的属性
tom.attack(maomao)
print('maomao当前血量为:',maomao.hp)
maomao.eat()
print('maomao吃药后血量为:',maomao.hp)
maomao.beat(tom)
print('tom当前血量:',tom.hp)
执行结果
我被调用了
tom_dict {'hp': 1000, 'job': '法师', 'name': 'tom', 'ad': 50}
我被调用了
maomao_dict {'hp': 500, 'name': 'maomao', 'ad': 10, 'kind': '泰迪'}
tom攻击了maomao,maomao掉了50点血
maomao当前血量为: 450
maomao吃药后血量为: 460
maomao咬了tom,tom掉了10点血
tom当前血量: 990