继承就是新建类的一种方式, 新建的类我们称为子类或者叫做派生类, 被继承的类我们称为父类或者基类
继承的特性是: 子类会遗传父类的属性
类解决了对象与对象之间代码冗余问题
继承解决了类与类之间代码冗余问题
class Parent1: pass class Parent2: pass class Sub1(Parent1, Parent2): pass
print(Sub1.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)
继承是描述子类与父类之间的关系, 是一种什么是什么的关系。要找出这种关系,必须先抽象再继承, 抽象即抽取类似或者说比较像的部分。
抽象分为两个层次:
继承: 基于抽象的结果,通过编程语言去实现它, 肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构
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') obj = Bar() # {} obj.f2() ''' 顺序: 对象自己(obj)-> 对象的类(Bar)-> 父类(Foo) -> 父类 '''
class Foo: def f1(self): print('Foo.f1') def f2(self): print('Foo.f2') self.f1() class Aoo: def f1(self): print('Aoo.f1') class Bar(Foo,Aoo): def f1(self): print('Bar.f1') obj = Bar() # {} obj.f2() ''' 父类顺序,按照从左往右循序查找,找完一条没有再重另外一条查找 顺序: 对象自己(obj)-> 对象的类(Bar)-> 父类(Foo) -> 父类(Aoo) -> 父类 '''
1. 什么是菱形继承 菱形继承是指一个类同时继承多个父类,父类或父类的父类最终都继承同一个类,例如 # 新式类:按照广度优先查询(如下图1) # 经典类:按照深度优先查询(如下图2) class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') pass class C(A): def test(self): print('from C') pass class D(B): def test(self): print('from D') pass class E(C): def test(self): print('from E') pass class F(D, E): def test(self): print('from F') pass
指名道姓访问某一个类的函数: 该方式与继承无关 class People: """由于学生和老师都是人,因此人都有姓名、年龄、性别""" school = 'oldboy' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Student(OldboyPeople): """由于学生类没有独自的__init__()方法,因此不需要声明继承父类的__init__()方法,会自动继承""" def choose_course(self): print('%s is choosing course' % self.name) class Teacher(OldboyPeople): """由于老师类有独自的__init__()方法,因此需要声明继承父类的__init__()""" def __init__(self, name, age, gender, level): People.__init__(self, name, age, gender) self.level = level # 派生 def score(self, stu_obj, num): print('%s is scoring' % self.name) stu_obj.score = num stu1 = Student('tom', 18, 'male') tea1 = Teacher('tony', 18, 'male', 10)
单继承使用super() 可以直接使用 class People: """由于学生和老师都是人,因此人都有姓名、年龄、性别""" school = 'oldboy' def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Student(OldboyPeople): """由于学生类没有独自的__init__()方法,因此不需要声明继承父类的__init__()方法,会自动继承""" def choose_course(self): print('%s is choosing course' % self.name) class Teacher(OldboyPeople): """由于老师类有独自的__init__()方法,因此需要声明继承父类的__init__()""" def __init__(self, name, age, gender, level): # People.__init__(self, name, age, gender) # super(People, self).__init__(self, name, age, gender) super().__init__(self, name, age, gender) self.level = level # 派生 def score(self, stu_obj, num): print('%s is scoring' % self.name) stu_obj.score = num
在多继承情况下,可以通过mro来查看查找顺序,super()是依赖于继承的,并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找
class Animal: #同一类事物:动物 def talk(self): pass class Cat(Animal): #动物的形态之一:猫 def talk(self): print('喵喵喵') class Dog(Animal): #动物的形态之二:狗 def talk(self): print('汪汪汪') class Pig(Animal): #动物的形态之三:猪 def talk(self): print('哼哼哼') #实例化得到三个对象 cat=Cat() dog=Dog() pig=Pig()
def Talk(animal): animal.talk()
# 我们可以在不考虑三者类型的情况下直接使用统计三个对象的长度 s.__len__() l.__len__() t.__len__() # Python内置了一个统一的接口 len(s) len(l) len(t)
import abc # 通过父类来限制子类 # 指定metaclass属性将类设置为抽象类,抽象类本身只是用来约束子类的,不能被实例化 class Animal(metaclass=abc.ABCMeta): @abc.abstractmethod # 该装饰器限制子类必须定义有一个名为talk的方法 def talk(self): # 抽象方法中无需实现具体的功能,也不能添加功能,只能pass pass class Cat(Animal): # 但凡继承Animal的子类都必须遵循Animal规定的标准 def talk(self): pass cat=Cat() # 若子类中没有一个名为talk的方法则会抛出异常TypeError,无法实例化
鸭子类型定义: 如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子
个人想法: 只要有相同的方法和属性,那就可以规划为同一个类