面向对象的三大特征- 继承

继承是一种创建新类的方式,继承表现的是什么是什么的概念,

在python中,新建的类可以继承一个或多个父类

父类又可称为基类或超类,新建的类称为派生类或子类

 

python中类的继承分为:单继承和多继承

class Fulei1: #定义父类
    pass

class Fulei2: #定义父类
    pass

class Zilei1( Fulei1): #单继承,基类是Fulei1,派生类是Zilei1
    pass

class Zilei2(Fulei1,Fulei2): #python支持多继承,用逗号分隔开多个继承的类
    pass

在python2中分新式类和经典类:

  经典类:如果你创建的类没有继承别的类,那这就是一个经典类,他的子类以及子类的子类都是经典类

  新式类:任意内置类型派生出的类都属于“新式类”,

而在python3中都是新式类,默认继承object

 

继承与抽象(先抽象再继承)抽象即抽取类似或者说比较像的部分

抽象最主要的作用是划分类别

比如狗和猫都是动物类

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

猫类和狗类都继承动物类,猫类可以实例化一个猫,狗类可以实例化一个狗

 

继承减少了代码的重复

比如猫和狗等所有的动物都会吃喝睡

而猫会喵喵叫,狗会汪汪叫,这样我们就可以抽像一个动物类,其中包括吃喝睡等方法,让猫类狗类继承他

如此一来就不必在狗类猫类中写吃喝睡方法了

class Animal:

    def eat(self):
        print("%s 吃 " %self.name)

    def drink(self):
        print ("%s 喝 " %self.name)

    def shit(self):
        print ("%s 拉 " %self.name)

    def pee(self):
        print ("%s 撒 " %self.name)


class Cat(Animal):

    def __init__(self, name):
        self.name = name
        self.breed = ''

    def cry(self):
        print('喵喵叫')

class Dog(Animal):

    def __init__(self, name):
        self.name = name
        self.breed=''

    def cry(self):
        print('汪汪叫')


# ######### 执行 #########

c1 = Cat('小白家的小黑猫')
c1.eat()

c2 = Cat('小黑的小白猫')
c2.drink()

d1 = Dog('胖子家的小瘦狗')
d1.eat()
用继承提高代码复用性

在开发程序的过程中,如果我们定义了一个类A,然后又想新建立另外一个类B,但是类B的大部分内容与类A的相同时

我们不可能从头开始写一个类B,这就用到了类的继承的概念。

通过继承的方式新建类B,让B继承A,B会‘遗传’A的所有属性(数据属性和函数属性),实现代码重用

子类对象的属性

如果子类中没有构造器,基类的构造器会被调用
class Animal:
    def __init__(self, name,aggressivity, life_value):
        self.name = name
        self.aggressivity = aggressivity
        self.life_value = life_value
class Dog(Animal):  # 定义一个狗类
    def bite(self,people):
        people.life_value -= self.aggressivity
wang = Dog("黑子",100,100)

print(wang.name)
#黑子

Dog类会创建一个实例并将实例和参数传入基类

#猜一下结果
class Foo:
    def __init__(self):
        self.func()

    def func(self):
        print('Foo.func')

class Son(Foo):
    def func(self):
        print('Son.func')

s = Son()
#Son.func
当创建Son实例时会将他的实例传进Foo的__init__()中,这个self并不知Foo的实例,而是Son的实例
当self调用func()时,自然就是Son中的func()了

 

当子类拥有自己的属性时,就需要在子类中定义一个构造器,此时基类的构造器必须显式的写出才会执行

#class Animal:
    def __init__(self,aggressivity, life_value,name):
        self.name = name  # 每一个角色都有自己的昵称;
        self.aggressivity = aggressivity  # 每一个角色都有自己的攻击力;
        self.life_value = life_value  # 每一个角色都有自己的生命值;
    def eat(self):
        self.life_value += 10

class Person(Animal):
    def __init__(self, name, aggressivity, life_value, money):
        Animal.__init__(self, name, aggressivity, life_value) #这是经典类和新式类都能用的
        #在新式类中还有一种super()方法
        #super().__init__(name, aggressivity, life_value)
        #super()在类中的时候括号里默认是子类名和self,所以__init__()里不用写self
        #super()在类外也可以用,需要传递子类名和一个子类的实例
        #super(Person,wang).eat()  == Animal.eat(wang)
        self.money = money    #派生属性:父类没有的属性

子类的对象调用方法时:

  子类中有则用子类的,没有则去父类中寻找

  如果子类和父类中都有想调用父类的:

    经典类 指名道姓 类名.方法名(子类对象) 类内外一致
    新式类 super方法 super(子类名,子类对象).方法名() 类内可以省略super的参数

  如果是想把子类和父类的方法都用,就直接把父类方法写进子类的同名方法里吧

经典类和新式类的多继承问题(钻石继承)

类名.mro()可以查看新式类继承顺序

在父类中查找方法的顺序

A类继承多个类,而继承的类不是子类,则按照类定义时继承的类从左往右查找

A继承BC,B和C继承D(B在前,C在后)

在经典类中,是先查找A,再去查B,再查D,最后查C。这就是深度优先,先把一条线查完

在新式类中,是先查找A,再去查B,再查C,最后查D。这就是广度优先,然而

如果是A继承BC,B继承E,C继承F,E和F继承D,

会先查A,再查找B,再去查E,再查C,最后查F,最后查D。并不像我们想象的那样查完B查C,

你也可以理解为一条单向的绳子只能子类去查父类,如果查完B去查C,那就查不到E了,

在最后查D的时候有两个子类指向D,就先不会查找他,直到最后一个指向D的子类时才会查找他

记住python3中都是新式类

 

posted @ 2017-11-21 16:26  瓜田月夜  阅读(82)  评论(0)    收藏  举报