day30

今日内容概要

  • 继承(面向对象中得核心)

    • 单继承 多继承

  • 单继承下的属性查找

  • 多继承下的属性查找

  • super和mro的使用

  • 多态和鸭子类型

继承(核心)

面向对象的三大特征:封装、继承、多态

1.什么是继承

继承就是一种新建类的方式,新建出来的类我们称为‘子类或者叫派生类’,被继承的类我们称之为是‘父类或者基类’

   当然出来的类子类可以遗传父类的所有属性

2.为什么要用继承

类解决了什么问题:对象与对象之间的代码冗余问题

继承解决了什么问题:类与类之间的代码冗余问题

3.怎么使用继承

经典类:没有继承object类的子子孙孙类都是经典类

新式类:继承了object类的子子孙孙类都是新式类

只有在python2中才区分经典类和新式类,如果是python3的版本,所有类都是新式类,也就是说在python3中默认的类都是继承了object类,在python3中没有了经典类和新式类的说法了

 class Parent1:passclass Parent2(object):pass

”Sub1继承了Parent1的类,Sub1就称为是子类,Parent1类就称为是父类或者叫基类“

单继承:一个类只继承了一个类,一个类继承了两个或者两个以上的类就是多继承了

class Sub1(Parent1):pass

多继承的类:Sub2就是子类,Parent1和Parent2都是父类

class Sub2(Parent1, Parent2):passprint(Sub1.__bases__) # (<class '__main__.Parent1'>,)
print(Sub2.__bases__) # (<class '__main__.Parent1'>, <class '__main__.Parent2'>)

继承的实际案例

class People():school = 'SH'def __init__(self, name, age, gender):self.name = nameself.age = ageself.gender = genderclass Student(People):def __init__(self, name, age, gender, course=None):if course is None:course = []"""子类里面一定再次调用父类的__init__方法"""People.__init__(self, name, age, gender) # 指名道姓的调用方法self.course = coursedef choose_course(self):print('%s 选课成功, %s' % (self.name, self.course))stu = Student('ly', 20, 'male')
print(stu.school)  # SH 属性的查找
print(stu.name)
print(stu.age)
print(stu.gender)class Teacher(People):def __init__(self, name, age, gender, level):People.__init__(self, name, age, gender)self.level = leveldef score(self, stu_name):print('%s 得了%s分' % (stu_name, 10))tea = Teacher('kevin', 19, 'female')
print(tea.name)
print(tea.age)
print(tea.gender)

属性查找

有了继承关系,对象在查找属性时,先从对象自己的__dict__中找,如果没有则去子类中找,然后再去父类中找.......

>>> class Foo:
...     def f1(self):
...         print('Foo.f1')
...     def f2(self):
...         print('Foo.f2')
...         self.f1()
... 
>>> class Bar(Foo):
...     def f1(self):
...         print('Foo.f1')
... 
>>> b=Bar()
>>> b.f2()
Foo.f2
Foo.f1

b.f2()会在父类Foo中找到f2,先打印Foo.f2,然后执行到self.f1(),即b.f1(),仍会按照:对象->类Bar->父类Foo的顺序依次找下去,在类Bar中找到f1,因而打印结果为Foo.f1

父类如果不想让子类覆盖自己的方法,可以采用双下划线开头的方式将方法设置为私有的

>>> class Foo:
...     def __f1(self): # 变形为_Foo__fa
...         print('Foo.f1') 
...     def f2(self):
...         print('Foo.f2')
...         self.__f1() # 变形为self._Foo__fa,因而只会调用自己所在的类中的方法
... 
>>> class Bar(Foo):
...     def __f1(self): # 变形为_Bar__f1
...         print('Foo.f1')
... 
>>> 
>>> b=Bar()
>>> b.f2() #在父类中找到f2方法,进而调用b._Foo__f1()方法,同样是在父类中找到该方法
Foo.f2
Foo.f1

继承的实现原理

菱形问题

大多数面向对象语言都不支持多继承,而在python中,一个子类是可以同时继承多个父类的,这固然可以带来一个子类可以对多个不同父类加以重用的好处,但也有可能引发著名的Diamond problem菱形问题(或称钻石问题,有时候也被称为“死亡钻石”),菱形其实就是对下面这种继承结构的形象比喻

 A类在顶部,B类和C类分别位于其下方,D类在底部将两者连接在一起形成菱形。

这种继承结构下导致的问题称之为菱形问题:如果A中有一个方法,B和/或C都重写了该方法,而D没有重写它,那么D继承的是哪个版本的方法:B的还是C的?如下所示

class A(object):def test(self):print('from A')class B(A):def test(self):print('from B')class C(A):def test(self):print('from C')class D(B,C):passobj = D()
obj.test() # 结果为:from B

要想搞明白obj.test()是如何找到方法test的,需要了解python的继承实现原理

继承原理

python到底是如何实现继承的呢?对于你定义的每一个类,Python都会计算出一个方法解析顺序(MRO)列表,该MRO列表就是一个简单的所有的基类的线性顺序列表如下

>>> D.mro() # 新式类内置了mro方法可以查看线性列表的内容,经典类没有该内置该方法
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

所以obj.test()的查找顺序是,先从对象obj本身的属性里找到方法test,没有找到,则参照属性查找的发起者(即obj)所处类D的MRO列表来依次检索,首先在类D中未找到,然后再B中找到方法test

1.由对象发起的属性查找,会从对象自身的属性里检索,没有则会按照对象的类.mro()规定的顺序依次找下去,
2.由类发起的属性查找,会按照当前类.mro()规定的顺序依次找下去,

深度优先和广度优先

参照下述代码,多继承结构为非菱形结构,此时,会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

class E:def test(self):print('from E')class F:def test(self):print('from F')class B(E):def test(self):print('from B')class C(F):def test(self):print('from C')class D:def test(self):print('from D')class A(B, C, D):# def test(self):#     print('from A')passprint(A.mro())
'''
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]
'''obj = A()
obj.test() # 结果为:from B
# 可依次注释上述类中的方法test来进行验证

 如果继承关系为菱形结构,那么经典类与新式类会有不同MRO,分别对应属性的两种查找方式:深度优先和广度优先

class G: # 在python2中,未继承object的类及其子类,都是经典类def test(self):print('from G')class E(G):def test(self):print('from E')class F(G):def test(self):print('from F')class B(E):def test(self):print('from B')class C(F):def test(self):print('from C')class D(G):def test(self):print('from D')class A(B,C,D):# def test(self):#     print('from A')passobj = A()
obj.test() # 如上图,查找顺序为:obj->A->B->E->G->C->F->D->object
# 可依次注释上述类中的方法test来进行验证,注意请在python2.x中进行测试

 

 

class G(object):def test(self):print('from G')class E(G):def test(self):print('from E')class F(G):def test(self):print('from F')class B(E):def test(self):print('from B')class C(F):def test(self):print('from C')class D(G):def test(self):print('from D')class A(B,C,D):# def test(self):#     print('from A')passobj = A()
obj.test() # 如上图,查找顺序为:obj->A->B->E->C->F->D->G->object
# 可依次注释上述类中的方法test来进行验证

super的使用

#A没有继承B,但是A内super会基于C.mro()继续往后找
class A:def test(self):super().test()
class B:def test(self):print('from B')
class C(A,B):passc=C()
c.test() #打印结果:from B

多态和鸭子类型

多态它是面向对象的三大特征之一

什么是多态?  同一种事物的多种形态

举例:

    水:气态水、液态水、固态水                                                                                                             动物:人 鸡 狗 猪等都是动物的一种形态

之所以说人、鸡、狗、猪是动物,是因为他们具备动物的特征,speak功能

import abc # abstract class 抽象类   具体的Specificclass Animal(metaclass=abc.ABCMeta): # 把animal类变成了抽象类"""父类中得方法不是为了实现逻辑的,实现功能的,而是单纯的为了限制子类的行为"""@abc.abstractmethod # 把抽象类中得方法变成抽象方法, 它不实现具体的功能,就是单纯的为了限制子类中的方法def speak(self):pass@abc.abstractmethoddef jiao(self):pass"""抽象类和普通类有什么区别? 抽象类只能够被继承、不能够被实例化"""# Animal() # Can't instantiate abstract class Animal with abstract methods speak"""怎么限制子类People类必须有speak功能? 我们可以在父类中来限制子类的行为,其实就是限制子类中必须有某些方法""""""Python崇尚的是鸭子类型""""""鸭子类型就是更多的关注的是对象的行为,而不是对象的类型"""class People(Animal):def speak(self):pass# print('from People.speak')def jiao(self):passclass Dog(Animal):def speak(self):passclass Pig(Animal):def speak(self):pass"""多态带来的特性:在不考虑对象类型的情况下,直接调用对象的方法或者属性"""
def animal(obj):return obj.speak()animal(obj)
animal(obj1)
animal(obj2)"""面试题:请举出Python中使用多态的例子:len"""len('hello')
len([1,2,3,4])
len((1,2,3,4))def len(obj):return obj.__len__
len('helloworld')
len([1,2,3,4])
len((1,2,3,4))

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/128797.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于maven的项目搭建(已跑通)

1、直接选择archetype-webapp即可 &#xff08;这里很多人会觉得很慢–解决方案&#xff1a;https://blog.csdn.net/qq_45591895/article/details/133705674?spm1001.2014.3001.5501&#xff09; 2、手动添加一个java目录即可。 3、添加Tomcat 3、这就跑通了&#xff0c;可以…

OpenCV实现求解单目相机位姿

单目相机通过对极约束来求解相机运动的位姿。参考了ORBSLAM中单目实现的代码&#xff0c;这里用opencv来实现最简单的位姿估计. mLeftImg cv::imread(lImg, cv::IMREAD_GRAYSCALE); mRightImg cv::imread(rImg, cv::IMREAD_GRAYSCALE); cv::Ptr<ORB> OrbLeftExtractor …

Mac navicat连接mysql出现1045 - Access denied for user ‘root‘

Mac navicat连接mysql出现1045 - Access denied for user ‘root’ 前提&#xff1a;如果你的mac每次开navicat都连接不上&#xff0c;推荐试试我这个方法 1.打开设置–>找到左下角最下面的MySQL–>点击Stop MySQL Server 2.开启一个终端&#xff0c;依次输入以下命令&a…

【MySQL】基本查询(二)

文章目录 一. 结果排序二. 筛选分页结果三. Update四. Delete五. 截断表六. 插入查询结果结束语 操作如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chi…

网站强制跳转至国家反诈中心该怎么办?怎么处理?如何解封?

在互联网环境中&#xff0c;网站安全是非常重要的。然而&#xff0c;在实际操作过程中&#xff0c;不少网站可能因内容问题、技术安全漏洞等原因被迫下线甚至跳转至国家反诈骗中心网址。面对这一严峻问题&#xff0c;我们如何有效解决&#xff0c;让网站恢复运行并解除强制跳转…

外汇天眼:三大方法提高容错率——成功投资者的秘密策略!

容错率是什么&#xff1f; 虽然A股市场投资体验不佳&#xff0c;但相较于中概股市场的波动&#xff0c;A股投资者仍有幸福感。以中概股的代表&#xff0c;金龙指数ETF为例&#xff0c;仅一年多时间内从85.90元下跌至20.47元&#xff0c;跌幅高达76%。 然而&#xff0c;有一位…

Spring实例化源码解析之Custom Events下集(九)

上集从官网的角度讲解了基本的使用和源码的内容&#xff0c;没有深入的进行分析&#xff0c;本章将从源码的角度分析ApplicationEvent、ApplicationListener、ApplicationEventMulticaster这三者之间的关系。 initApplicationEventMulticaster 上一章后续部分给出了源码的含义…

PTE阶段规划

目录 复习的各个阶段 线下应该如何 rs应对 从来都是流利度大于内容 推荐的练习网站 口语 DI 关键词是不能念错 口语 RL rl每日练习方法 ASQ 写作 swt 阅读 一半靠机经 听力 口语和听力 考模版来熟悉 熟悉模版 强调的是&#xff0c;整个的逻辑思维 字字和句句都…

使用运放产生各种波形

目录复制 文章目录 RC正弦振荡电路文氏电桥振荡电路移项式正弦波振荡电路 集成函数发生器运算放大器驱动电容性负载峰值检波多通道运放未使用的运放接法 RC正弦振荡电路 文氏电桥振荡电路 这个振荡器起振条件RF > 2R1,起振后又希望RF 2R1产生矛盾怎么办&#xff1f; 将RF换…

IP 子网划分(VLSM)

目录 一、 为什么要划分子网 二、如何划分子网 1、划分两个子网 2、划分多个子网 一、 为什么要划分子网 假设有一个B类IP地址172.16.0.0&#xff0c;B类IP的默认子网掩码是 255.255.0.0&#xff0c;那么该网段内IP的变化范围为 172.16.0.0 ~ 172.16.255.255&#xff0c;即…

SpringMVC系列-4 参数解析器

背景&#xff1a; 本文作为SpringMVC系列的第四篇&#xff0c;介绍参数解析器。本文讨论的参数解析表示从HTTP消息中解析出JAVA对象或流对象并传参给Controller接口的过程。 本文内容包括介绍参数解析器工作原理、常见的参数解析器、自定义参数解析器等三部分。其中&#xff0…

蓝桥等考Python组别十六级002

第一部分:选择题 1、Python L16 (15分) a和b是两个集合,它们的关系如下图所示: 以下哪个表达式的值是True?( ) a > ba < ba == ba >= b正确答案:B 2、Python