面向对象 类的继承(初识篇)

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值