面向对象的三大特征- 继承
继承是一种创建新类的方式,继承表现的是什么是什么的概念,
在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中都是新式类

浙公网安备 33010602011771号