类的三大特性-继承
day 22
面向对象之继承:
一、继承简述:
1、继承的定义:
继承描述的是一种类与类之间的关系,即子类与父类的关系。
继承是一种创建新式类的方式,新建的类可以继承一个或多个父类(Python支持多继承),父类又称为超类或基类,新建的类则称为派生类或者子类。
##新式类与经典类的区分: 首先:新式类指的是直接或间接的继承了object类的类。 1.只有在python2中才分新式类和经典类,python3中统一都是新式类 2.在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类 3.在python2中,显式地声明继承object的类,以及该类的子类,都是新式类 3.在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
2、继承的特性:
子类会“遗传”父类的属性,这种特性决定了它解决代码冗余的特点。
# python中的单继承与多继承 class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass class SubClass2(ParentClass1,ParentClass2): #python支持多继承,多个父类之间用逗号分隔开 pass #--》查看继承结果: >>> SubClass1.__bases__ #(查看继承结果的方法)#__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
3、抽象
前面叙述继承是一种类与类之间的关系,要找出这种关系就必须先抽象。
抽象:此处是指抽取对象之间比较相似或者比较像的部分。
抽象分为两个层次:
a、抽取对像与对象之间相似的部分,从而定义出类。
b、从两个类中在抽取出相似的部分,从而有了父类。
注:抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。
#通过抽取提取对象中的相似部分得到类,在通过提取类与类之间相似的部分得到父类 ==========================第一部分 例如 猫可以:喵喵叫、吃、喝、拉、撒 狗可以:汪汪叫、吃、喝、拉、撒 如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实现他们所有的功能,伪代码如下: #猫和狗有大量相同的内容 class 猫: def 喵喵叫(self): print '喵喵叫' def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something class 狗: def 汪汪叫(self): print '喵喵叫' def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something ==========================第二部分 上述代码不难看出,吃、喝、拉、撒是猫和狗都具有的功能,而我们却分别的猫和狗的类中编写了两次。如果使用 继承 的思想,如下实现: 动物:吃、喝、拉、撒 猫:喵喵叫(猫继承动物的功能) 狗:汪汪叫(狗继承动物的功能) 伪代码如下: class 动物: def 吃(self): # do something def 喝(self): # do something def 拉(self): # do something def 撒(self): # do something # 在类后面括号中写入另外一个类名,表示当前类继承另外一个类 class 猫(动物): def 喵喵叫(self): print '喵喵叫' # 在类后面括号中写入另外一个类名,表示当前类继承另外一个类 class 狗(动物): def 汪汪叫(self): print '喵喵叫' ==========================第三部分 #继承的代码实现 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()
4、派生
派生指的是子类继承某个父类的所有属性,并且还拥有自己独有的属性或技能,此种子类则称之为派生类。(即子类中出现了任何新内容,则此子类就是一个派生类)
class People: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def sayHI(self): print("hello 我是%s 今年%s岁 性别:%s" % (self.name,self.age,self.sex)) # Test不能称为派生类 , 因为没与任何独特的内容与父类完全一致 class Test(People): pass # 派生类属于子类吗? 派生类一定是某个子类,但是子类不一定是派生类 # Student类就称为 Person类的派生类 class Student(People): def __init__(self,name,age,sex,number): super().__init__(name,age,sex) self.number = number # 上课 def take_class(self): print("%s 正在上课.....")
5、子类访问父类中属性的方法
#########父类######### class People: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex print(self) def sayHI(self): print("hello 我是%s 今年%s岁 性别:%s" % (self.name,self.age,self.sex)) class Student(People): def __init__(self,name,age,sex,number): #子类访问父类的方式一:(指名道姓的进行调用) People.__init__(self,name,age,sex) # 子类中重用父类种方法的方式二 # super() # 表示创建一个特殊的对象 用于调用父类的方法 # super().__init__(name,age,sex) # 了解:在python2中 super的使用方式有所不同 需要传入当前类,当前对象 #super(Student,self).__init__(name,age,sex) self.number = number # 上课 def take_class(self): print("%s 正在上课.....") stu1 = Student("阿三",20,"woman","9527") print(stu1) print(stu1.name,stu1.age,stu1.sex)
6、属性查找:
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() class Bar(Foo): def f1(self): print('Bar.f1') b=Bar() b.f2() #result:Foo.f2 # Bar.f1 #注:属性查找遵循的定律始终是现在自己的名称空间中查找属性——》父类。。。最后抛出异常(没找到) #python中提供了一个查看属性的查找顺序的方法(类名.mro()) class S: pass class Student(S): pass # __bases__用于查看父类 print(Student.__bases__) # 显示属性的查找顺序列表,属性查找属性就是按照该列表来查找的 print(Student.mro())
注:当继承的多个父类存在共通父类时,会产生菱形继承的关系,此时的查找顺序为先深度优先,再广度优先。
没有菱形继承的关系时,查找顺序会沿着一条路径找到低,如果没有再找其他路径(深度优先)的查找方式进行查找。