继承
1.继承介绍
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
1.1.什么是继承
继承一种新建类的方式,新建的类称之为子类/派生类,被继承的类称之为父类\基类\超类
python中继承的特点:
1.2.为何要用继承
1.3.如何用继承
语法
class 父类:passclass 子类(父类):pass
实例
class Parent1:xxx = 333def run(self):print('我是父类的方法')class Sub1(Parent1):# xxx = 222# def run(self):# print('我是子类的方法')passobj = Sub1()# obj.xxx=111# 对象 << 类 << 父类print(obj.xxx)obj.run()
2.利用继承来解决类和类直接的代码冗余问题
我们先思考一个问题:请看图

1.对象和类的关系
奥巴马和梅西都有人的特征,麦兜和猪坚强都有猪的特征,史努比和史派克都有狗的特征
所以总结对象的相似之处得到了类
2.类和父类的关系
例子
学生类和老师类都是人,所以他们具有人相同的特征
# @Author : 大海# @File : 2.利用继承来解决类和类之间的代码冗余问题.py'''总结对象的相似之处得到了类总结类的相似之处得到父类'''class People:school = '图灵学院'def __init__(self,name,age,sex):self.name = nameself.age = ageself.sex = sexclass Student(People):# def __init__(self,name,age,sex):# self.name = name# self.age = age# self.sex = sexdef play(self):print('%s play football' % self.name)class Teacher(People):# def __init__(self,name,age,sex):# self.name = name# self.age = age# self.sex = sexdef course(self):print('%s course'%self.name)# 实例化的时候子类没有__init__方法会调用父类的stu1 = Student('周阳',30,'male')print(stu1.__dict__)tea1 = Teacher('大海',31,'man')print(tea1.__dict__)# 但是这里有个问题子类有新的属性需要实例化的时候参数怎么办
继承是一种新建类的方式,新建的类称之为子类/派生类,被继承 的类称之为父类\基类\超类
python中继承的特点: 子类可以遗传/重用父类的属性
派生
1.什么是派生
指的是子类继承父类的属性和方法,并且派生出自己独有的属性与方法。
2.为什么要派生
子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找,
例如每个学生还有分数这一属性,我们就需要在Student类中定义该类自己的
init方法去覆盖父类的(因为优先用子类的方法)
子类派生重用父类功能一
子类重用父类的功能,在子类派生出的新方法中重用父类功能的方式一:指名道姓地引用某个类中的函数。
class People:school='图灵学院'def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexclass Student(People): #这里即使没有引用父类,代码也能下常运行#写个默认参数def __init__(self,name,age,sex,score=0):People.__init__(self,name,age,sex) #指明方法 引用并修改self.score=scoredef play(self):print('%s play football'%self.name)class Teacher(People): # 子类在父类的基础上添加一个新的形参def __init__(self,name,age,sex,hoppy):People.__init__(self,name,age,sex)self.hoppy=hoppydef course(self):print('%s course'%self.name)stu1=Student('周阳',30,'male')print(stu1.__dict__)tea1=Teacher('大海',31,'男','篮球')print(tea1.__dict__)
子类派生重用父类功能二
派生实例化除了父类的属性添加,还能有自己独有的属性
在子类派生出的新方法中重用父类功能的方式二:super()必须在类中用
super(自己的类名,自己的对象)
可以省略传值
super()
class People:school='图灵学院'def __init__(self,name,age,sex):self.name=nameself.age=ageself.sex=sexclass Student(People):#写个默认参数def __init__(self,name,age,sex,score=0):super(Student,self).__init__(name,age,sex)# 也可省略传值 super().__init__(name,age,sex)self.score=score
单继承背景下的属性查找
4.1.在单继承背景下的属性查找顺序
# @Author : 大海# @File : 4.在单继承背景下的属性查找.py# 在单继承背景下属性的查找优先级:对象->对象的类->父类->父类.....->objectclass Foo():xxx = 444passclass Bar1(Foo):xxx = 333passclass Bar2(Bar1):xxx = 222passobj = Bar2()# obj.xxx=111print(obj.xxx)
例子
class Foo:def f1(self):print('Foo.f1')def f2(self):print('Foo.f2')# obj.f1()是Bar()的对象self.f1()class Bar(Foo):def f1(self):print('Bar.f1')obj=Bar()obj.f2()
多继承背景下的属性查找
广度优先查找
例子
# @Author : 大海# @File : 5.在多继承背景下的属性查找.py# 在多继承背景下属性的查找优先级: **# 此时属性的查找优先级是:对象->对象的类->按照从左往右的顺序一个分支一个分支的找下去# 广度优先查找,从左往右一个分支一个分支的查找,在最后一个分支才去查找顶级类# 第四层 # 顶级类是在最后一个分之才走的class G():x = 'G'pass# 第三层class E(G):# x = 'E'passclass F(G):# x='F'pass# 第二层class B(E):# x= "B"passclass C(F):# x='C'passclass D(G):# x='D'pass# 第一层class A(B,C,D):# x = 'A'passobj = A()# obj.x = 111print(obj.x)# python专门为继承类内置了一个mro的方法,用来查看c3算法的计算结果print(A.mro())
优先级:对象》对象的类》按照从左往右的顺序一个分支一个分支的找下去
广度优先查找,从左往右一个分支一个分支的查找, 在最后一个分支才去查找 顶级 类
在多继承背景下的属性查找
mro方法
python 专门为继承类内置了一个mro的方法,用来查看c3算法的计算结果(查看子类继承属性的优先级)
print(A.mro()) #A为一子类,这里主要展示mro方法格式
组合
组合指的是某一个对象拥有一个属性,该属性的值是另外一个类的对象
为何使用组合:
通过为某一个对象添加属性(属性的值 是另外 一个类的对象)的方式,可以间接地将两个类关联、整合、组合到一起,从而减少类与类之间代码的冗余。
class Foo:xxx=111class bar:yyy=222def zzz(self):print('bar的方法')obj=Foo()obj1=bar()#obj.attr='大海’ --->添加新值,创建属性#print(obj.attr)obj.attr=obj1 #---->添加对象,进行组合# 组合在一起,obj.attr 等价于obj1print(obj.xxx)print(obj.attr.yyy)obj.attr.zzz()
class People:school = '图灵学院'def __init__(self,name,age,sex):self.name = nameself.age = ageself.sex = sexclass Student(People):def __init__(self, name, age, sex,score=0):super().__init__(name, age, sex)self.score = scoreclass Teacher(People):def __init__(self,name,age,sex,course=[]):super().__init__(name, age, sex)self.course=coursedef tell_info1(self):# 这个时候是列表里面装了4个课程对象# print(self.course)for i in self.course:# print(i)# 课程属性# print('<课程名:%s,价格%s>' % (i.c_name, i.c_price))# 课程方法i.tell_info()class Course:def __init__(self,c_name,c_price):self.c_name = c_nameself.c_price = c_pricedef tell_info(self):print('<课程名:%s,价格%s>'%(self.c_name,self.c_price))python = Course('python开发',10000)math = Course('高等数学',3000)English = Course('英语',4000)music = Course('音乐',5000)drawing = Course('绘画',6000)dahai = Teacher('大海',24,'man')# print(dahai)# 把music课程对象添加到老师对象tea的属性里面# dahai.course = music# print(dahai.course)# print(music)# dahai.course.tell_info()# dahai.course = math# dahai.course.tell_info()# 如果我想把一堆的对象放到一个对象属性里面,我们怎么做?# 思考一下? 放到一个容器里面 列表# print(dahai.course)# dahai.course = music# print(dahai.course)dahai.course.append(python)dahai.course.append(math)dahai.course.extend([English,music])# 这个时候是列表里面装了4个课程对象print(dahai.course)print('===================')dahai.tell_info1()
组合和继承的区别:
继承是把全部的属性和方法让子类可以调用,而组合只是部分的属性和方法把2个类关联到一起,
有些类的属性不能全部继承,这就用到了组合,组合的是对象,而继承 的是,类
继承 是在类定义产生的,它是类之间的关联关系,
而组合是类定义后产生的关系,因为它是对象的关联关系
8.多态
8.1.什么是多态
多态指的是同一种/类事物的不同形态,比如动物有多种形态:猫,狗,猪。
8.2.为何要用多态
多态性:在多态的背景下,可以在不用考虑对象具体类型的前提下而直接使用对象
多态性的精髓:统一
8.3.如何用多态
1.定义一个多态性的方法
class Animal:# 动物都会叫def speak(self):print('我是动物我会说话')class People(Animal):def speak(self):print('say hello')class Dog(Animal):def speak(self):print('汪汪汪')class Pig(Animal):def speak(self):print('哼哼哼')# 三个对象都是动物obj1=People()obj2=Dog()obj3=Pig()
2.多态性的精髓:统一
多态性的好处在于增强了程序的灵活性和可扩展性,比如通过继承Animal类创建了一个新的类型,实例化得到的对象obj,可以使用相同的方式使用object.speak()
# 多态性的精髓:统一# 学车,学的是小汽车标准,会了所有的小汽车都会开obj1.speak()obj2.speak()obj3.speak()# 内置方法多态方法# len()# 计算多个值的长度
3.python中一切皆对象,数据类型本身就是对象,本身就支持多态性
print(len([1, 2, 3, 4]))print(len('1234'))print(len((1, 2, 3, 4)))# 计算多个值的长度,如果按照以下这样就缺乏了多态性,灵活性就弱# size()# zhangdu()# kuangdu()
9.常用的魔法方法
9.1. str
在对象被打印时自动触发,可以用来定义对象被打印时的输出信息
class People:def __init__(self,name,age):self.name = nameself.age = agedef __str__(self):return '<name:%s age%s>'%(self.name,self.age)def run(self):return self.nameobj = People('大海',18)print(obj)print(obj.run())
9.2. del
在对象被删除时先自动触发该方法,可以用来回收对象以外其他相关资源,比如系统资源
# # __del__# import timeclass Foo:def __init__(self,x,filepath,encoding='utf8'):self.x=xself.f=open(filepath,'rt',encoding=encoding)def __del__(self):print('__del__正在运行')self.f.close()obj = Foo(1,'a.txt')# # print(obj.f.read())# # obj.f.close()# print('不是对象生成运行__del__,对象正在使用的时候不会运行')# time.sleep(3)# 对象使用不会运行__del__# print(obj.f.read())
9.3. call
在对象被调用时会自动触发该方法
# __call__: 在对象被调用时会自动触发该方法class Foo:def __init__(self,name,age):self.name = nameself.age = agedef __call__(self, *args, **kwargs):print(self,args,kwargs)def run(self):print('run')obj1 = Foo(1,2)obj1.run()# 没写__call__不可以调用# obj1()# 写了__call__可以调用# obj1()# obj1(1,2,x=3,y=4)# # 省略了# obj1.__call__(1,2,x=3,y=4)
