面向对象:继承

定义:新建的一个类继承另外一个类,另外一个类称为父类,也称为基类或超类。新建的类称为派生类或者子类
作用:减少代码的重复性,提高可读性,规范编程方式
继承分为新式类和经典类,又分为单继承和新继承
经典类:python2当中默认为经典类,继承object后为新式类
新式类:python3当中只有新式类,默认继承object,拥有方法mro,用于解析类的执行顺序
单继承:直接找父类
多继承:钻石继承最为经典,在经典类中,钻石继承为深度优先,而在新式类中,为广度优先。
  广度优先:新式类
  深度优先:经典类
派生:子类在父类的方法和属性的基础上产生了新的属性和方法,称为派生属性和派生方法
单继承:
class A:
    pass

class B(A):
    pass
多继承:
class A:
    pass

class B:
    pass

class C(A,B):
    pass

 

例:
# 下方的人狗大战,代码重复性太高,人是动物,狗是动物,他们有相同的属性,这时则可以创建一个动物类,让人和狗继承这个类,即动物为父类,人和狗为子类。

class Person:
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex
    def kick(self,dog):
        dog.hp -= self.aggr
        return '%s踢了狗%s,狗剩余%s血'%(self.name,dog.name,dog.hp)


class Dog:
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex

    def bite(self,person):
        person.hp -= self.aggr
        return '狗%s咬了%s,人剩余%s血'%(self.name,person.name,person.hp)

aike = Person('aike',1000,100,'')
chenfan = Dog('chenfan',500,50,'taddy')
print(aike.kick(chenfan))
print(chenfan.bite(aike))
使用继承后:
class Animal:  #父类,基类,超类
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex

class Person(Animal):  #子类,派生类
    def kick(self,dog):
        dog.hp -= self.aggr
        return '%s踢了狗%s,狗剩余%s血'%(self.name,dog.name,dog.hp)

class Dog(Animal):    #子类,派生类
    def bite(self,person):
        person.hp -= self.aggr
        return '狗%s咬了%s,人剩余%s血'%(self.name,person.name,person.hp)

aike = Person('aike',1000,100,'')
chenfan = Dog('chenfan',500,50,'taddy')
print(aike.kick(chenfan))
print(chenfan.bite(aike))

单继承,派生属性、派生方法、super方法:
class Animal:  #父类,基类,超类 ,python当中所有父类默认继承object类
    def __init__(self,name,hp,aggr,sex):
        self.name = name
        self.hp = hp
        self.aggr = aggr
        self.sex = sex
    def func1(self):
        print('测试super')

class Person(Animal):  #子类,派生类
    def __init__(self,name,hp,aggr,sex,money): #人要有钱这个属性
        # Animal.__init__(self,name,hp,aggr,sex)
        # super().__init__(name,hp,aggr,sex)#super,等同于上一句的类调用,但是不用传self,因为在类的内部使用super方法,默认找父类,不用填写参数,等同于下面一句代码
        super(Person,self).__init__(name,hp,aggr,sex)#括号内为自己的类名
        self.money = money #钱属于派生属性
    def kick(self,dog): #派生方法
        dog.hp -= self.aggr
        return '%s踢了狗%s,狗剩余%s血'%(self.name,dog.name,dog.hp)
    def person_weapon(self,weapon): #获取武器
        if (self.money - weapon.price) > 0:
            self.money -= weapon.price
            self.weapon = weapon
            self.aggr += weapon.aggr
        else:
            return '赶紧充钱'

class Dog(Animal):    #子类,派生类
    def bite(self,person): #派生方法
        person.hp -= self.aggr
        return '狗%s咬了%s,人剩余%s血'%(self.name,person.name,person.hp)

class Weapon: #用钱可以买武器
    def __init__(self,name,price,aggr):
        self.name = name
        self.price = price
        self.aggr = aggr
    def func(self):
        pass

aike = Person('aike',1000,100,'',1000)
chenfan = Dog('chenfan',500,50,'taddy')
stick = Weapon('stick',200,50)
aike.person_weapon(stick)#装上武器+50攻击
print(aike.kick(chenfan))
print(chenfan.bite(aike))
print(aike.money) #装上武器,钱减少
super(Person,aike).func1()#在类外部使用需要传子类名和对象,调用方法时,只能调用父类的方法。
结论:
1、父类中没有的属性 在子类中出现 叫做派生属性
2、父类中没有的方法 在子类中出现 叫做派生方法
3、只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错
4、super方法:只在新式类中才有,作用是调用父类的方法,与父类名调用方法的作用相同,但是父类名调用需传self。
在类中使用不用填参数,默认找父类,不用传self
在类外部使用需要传子类名和对象,调用方法时,只能调用父类的方法。

多继承:
#钻石继承1
class A:
    def func(self):
        print('这是A')
class B(A):
    def func(self):
        print('这是B')
class C(A):
    def func(self):
        print('这是C')
class D(B,C):
    def func(self):
        print('这是D')

d = D()
d.func()
python3当中只有新式类,调用顺序遵循广度优先: D-->B-->C-->A
#钻石继承2
class A:
    def func(self):
        print('这是A')
class B(A):
    def func(self):
        print('这是B')
class E:
    def func(self):
        print('这是E')
class C(E):
    def func(self):
        print('这是C')
class D(B,C):
    def func(self):
        print('这是D')

d = D()
d.func()
print(D.mro())#[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.C'>, <class '__main__.E'>, <class 'object'>]
python3当中只有新式类,调用顺序遵循广度优先: D-->B-->A-->C-->E


#钻石排列3
class A:
    def func(self):
        print('这是A')
class B(A):
    def func(self):
        print('这是B')
class C(A):
    def func(self):
        print('这是C')
class E(B):
    def func(self):
        print('这是E')
class F(C):
    def func(self):
        print('这是F')
class D(E,F):
    def func(self):
        print('这是D')

d = D()
d.func()
print(D.mro())#[<class '__main__.D'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.F'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
python3当中只有新式类,调用顺序遵循广度优先: D-->E-->B-->F-->C-->A

 

经典类为深度优先:即一条路找到低,找不到则换一条路。

关于super:

class A:
    def func(self):
        print('这是A')
class B(A):
    def func(self):
        super().func()
        print('这是B')
class C(A):
    def func(self):
        super().func()
        print('这是C')
class D(B,C):
    def func(self):
        super().func()
        print('这是D')

d = D()
d.func()

#打印为:
这是A
这是C
这是B
这是D

super的本质:不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的,所以寻找顺序为D-->B-->C-->A

posted @ 2019-09-03 18:28  aikell  阅读(175)  评论(0编辑  收藏  举报