Python奇幻之旅(从入门到入狱高级篇)——面向对象进阶篇(下)

目录

引言

3. 面向对象高级和应用

3.1. 继承【补充】

3.1.1. mro和c3算法

c3算法

一句话搞定继承关系

3.1.2. py2和py3区别

3.3. 异常处理

3.3.1. 异常细分

3.3.2. 自定义异常&抛出异常

3.3.3. 特殊的finally

3.4. 反射

3.4.1. 一些皆对象

3.4.2. import_module + 反射

结尾


引言

本篇文章主要是有关面向对象更加进阶一些的内容,主要是讲解了mro和C3算法,明确了Python中的继承关系,并且介绍了如何做异常处理和如何通过字符串去对象中拿元素

3. 面向对象高级和应用

3.1. 继承【补充】

对于Python面向对象中的继承,我们已学过:

  • 继承存在意义:将公共的方法提取到父类中,有利于增加代码重用性。
  • 继承的编写方式:
# 继承
class Base(object):passclass Foo(Base):pass

调用类中的成员时,遵循:

  • 优先在自己所在类中找,没有的话则去父类中找。
  • 如果类存在多继承(多个父类),则先找左边再找右边。

3.1.1. mro和c3算法

如果类中存在继承关系,可以通过mro()获取当前类的继承关系(找成员的顺序)。

class A:def method(self):print("A")class B(A):def method(self):print("B")class C(A):def method(self):print("C")class D(B, C):pass# 输出方法解析顺序
print(D.__mro__)# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
c3算法

C3算法基于一些原则来确定MRO:

  1. 子类优先: 在继承链中,子类的方法优先于父类的方法。

  2. 从左到右: 在同一层级的继承关系中,按照从左到右的顺序查找方法。

  3. 深度优先: 在多重继承中,首先深度优先搜索,然后从左到右搜索。

我们可以先来看一个例子:

这是继承结构图:

 

class D(object):passclass C(D):passclass B(D):passclass A(B, C):passprint(A.mro()) # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]

C3算法的核心是通过合并(merge)原则来计算MRO

所以我们首先得知道什么是merge,其实这就是一个函数

这个函数接受合并参数,主要根据以下规则来进行计算:

  1. 从所有候选的列表头中选择第一个,如果该头在其它列表的除第一个以外里面,就排除掉这个头,继续选择下一个头。
  2. 重复这个过程,直到所有的列表都为空或者没有可以选择的头。

下面演示了C3算法中的merge函数和合并过程:

mro(A) = [A] + merge( mro(B), mro(C), [B,C])   # A代表当前类,然后继续找B,C的父类,最后一个参数就代表当前类的本层继承父类# 然后开始拆分:
# B,C都继承了D类,所以如下(当然这里没有考虑object,因为这肯定是最后的基类):
mro(A) = [A] + merge( [B,D], [C,D], [B,C])
# 然后从第一个[B,D]的B开始找,找后面除头部以外的其他的,看有没有B,如果没有B,就删除,并且加入队列(也就是最后A的mro继承顺序)mro(A) = [A] + [B,C,D] 
# 最后直接合并
mro(A) = [A,B,C,D]

当然,以上分析起来十分麻烦,如果遇到很多的继承关系,分析起来就难上加难了,比如:

当然,没理解也没关系,我下面会继续讲解一个更好的方法:

 

一句话搞定继承关系

如果用正经的C3算法规则去分析一个类继承关系有点繁琐

所以,这里总结了一句话:从左到右,深度优先,大小钻石,留住顶端,基于这句话可以更快的找到继承关系。

大概意思就是:

  1. 从左到右: 先从左往右开始找

  2. 深度优先: 继续往当前子类,往下面的深度扩展

  3. 大小钻石: 如果遇到菱形的,就要特殊处理

  4. 留住顶端: 先跳过父类,等到右边的时候,再往父类去找

 过程:

  • 先找A,A的子类是B,C,P,所以先往B找
  • 到达B,然后深度搜索,往B的下面找,也就是D
  • D继续往下面找,也就是G,H,K,然后返回
  • 发现E,B,C,A构成了菱形,所以先跳过E,找到C
  • 然后C又开始往下面找,这个时候可以找E了,然后就是E
  • 到达E,发现又是菱形,所以先找F
  • F之后就是M,N,最后返回就是P
  • 最后就是基类
简写为:A -> B -> D -> G -> H -> K -> C -> E -> F -> M -> N -> P -> object

通过这种方法,可以很快解析继承关系,可以在网上找找视频结合本篇文章,食用更佳。

3.1.2. py2和py3区别

概述:

  • 在python2.2之前,只支持经典类【从左到右,深度优先,大小钻石,不留顶端】
  • 后来,Python想让类默认继承object(其他语言的面向对象基本上也都是默认都继承object),此时发现原来的经典类不能直接集成集成这个功能,有Bug。
  • 所以,Python决定不再原来的经典类上进行修改了,而是再创建一个新式类来支持这个功能。【从左到右,深度优先,大小钻石,留住顶端。】
    • 经典类,不继承object类型
class Foo:pass

    • 新式类,直接或间接继承object
class Base(object):passclass Foo(Base):pass

  • 这样,python2.2之后 中就出现了经典类和新式类共存。(正式支持是2.3)
  • 最终,python3中丢弃经典类,只保留新式类。

Py2:

  • 经典类,未继承object类型。【从左到右,深度优先,大小钻石,不留顶端】
class Foo:pass
  • 新式类,直接获取间接继承object类型。【从左到右,深度优先,大小钻石,留住顶端 -- C3算法】
class Base(object):passclass Foo(Base):pass

Py3

  • 新式类,丢弃了经典类只保留了新式类。【从左到右,深度优先,大小钻石,留住顶端 -- C3算法】
class Foo:passclass Bar(object):pass

3.3. 异常处理

在程序开发中如果遇到一些 不可预知的错误 或 你懒得做一些判断 时,可以选择用异常处理来做。

import requestswhile True:url = input("请输入要下载网页地址:")res = requests.get(url=url)with open('content.txt', mode='wb') as f:f.write(res.content)

上述下载视频的代码在正常情况下可以运行,但如果遇到网络出问题,那么此时程序就会报错无法正常执行。

如果使用异常处理,那么程序就不会报错,继续往下面执行

try:res = requests.get(url=url)
except Exception as e:代码块,上述代码出异常待执行。
print("结束")

异常处理的基本格式:

try:# 逻辑代码
except Exception as e:# try中的代码如果有异常,则此代码块中的代码会执行。

try:# 逻辑代码
except Exception as e:# try中的代码如果有异常,则此代码块中的代码会执行。
finally:# try中的代码无论是否报错,finally中的代码都会执行,一般用于释放资源。print("end")"""
try:file_object = open("xxx.log")# ....
except Exception as e:# 异常处理
finally:file_object.close()  # try中没异常,最后执行finally关闭文件;try有异常,执行except中的逻辑,最后再执行finally关闭文件。
"""

3.3.1. 异常细分

import requestswhile True:url = input("请输入要下载网页地址:")try:res = requests.get(url=url)except Exception as e:print("请求失败,原因:{}".format(str(e)))continuewith open('content.txt', mode='wb') as f:f.write(res.content)

之前只是简单的捕获了异常,出现异常则统一提示信息即可。如果想要对异常进行更加细致的异常处理,则可以这样来做:

import requests
from requests import exceptionswhile True:url = input("请输入要下载网页地址:")try:res = requests.get(url=url)print(res)    except exceptions.MissingSchema as e:print("URL架构不存在")except exceptions.InvalidSchema as e:print("URL架构错误")except exceptions.InvalidURL as e:print("URL地址格式错误")except exceptions.ConnectionError as e:print("网络连接错误")except Exception as e:print("代码出现错误", e)# 提示:如果想要写的简单一点,其实只写一个Exception捕获错误就可以了。

对错误进行细分的处理,例如:发生Key错误和发生Value错误分开处理。

基本格式:

try:# 逻辑代码passexcept KeyError as e:# 只捕获try代码中发现了键不存在的异常,例如:去字典 info_dict["n1"] 中获取数据时,键不存在。print("KeyError")except ValueError as e:# 只捕获try代码中发现了值相关错误,例如:把字符串转整型 int("诶器")print("ValueError")except Exception as e:# 处理上面except捕获不了的错误(可以捕获所有的错误)。print("Exception")

Python中内置了很多细分的错误,供你选择。

常见异常:
"""
AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x
IOError 输入/输出异常;基本上是无法打开文件
ImportError 无法引入模块或包;基本上是路径问题或名称错误
IndentationError 语法错误(的子类) ;代码没有正确对齐
IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问n x[5]
KeyError 试图访问字典里不存在的键 inf['xx']
KeyboardInterrupt Ctrl+C被按下
NameError 使用一个还未被赋予对象的变量
SyntaxError Python代码非法,代码不能编译(个人认为这是语法错误,写错了)
TypeError 传入对象类型与要求的不符合
UnboundLocalError 试图访问一个还未被设置的局部变量,基本上是由于另有一个同名的全局变量,
导致你以为正在访问它
ValueError 传入一个调用者不期望的值,即使值的类型是正确的
"""
更多异常:
"""
ArithmeticError
AssertionError
AttributeError
BaseException
BufferError
BytesWarning
DeprecationWarning
EnvironmentError
EOFError
Exception
FloatingPointError
FutureWarning
GeneratorExit
ImportError
ImportWarning
IndentationError
IndexError
IOError
KeyboardInterrupt
KeyError
LookupError
MemoryError
NameError
NotImplementedError
OSError
OverflowError
PendingDeprecationWarning
ReferenceError
RuntimeError
RuntimeWarning
StandardError
StopIteration
SyntaxError
SyntaxWarning
SystemError
SystemExit
TabError
TypeError
UnboundLocalError
UnicodeDecodeError
UnicodeEncodeError
UnicodeError
UnicodeTranslateError
UnicodeWarning
UserWarning
ValueError
Warning
ZeroDivisionError
"""

3.3.2. 自定义异常&抛出异常

上面都是Python内置的异常,只有遇到特定的错误之后才会抛出相应的异常。

其实,在开发中也可以自定义异常。

class MyException(Exception):pass

try:pass
except MyException as e:print("MyException异常被触发了", e)
except Exception as e:print("Exception", e)

上述代码在except中定义了捕获MyException异常,但他永远不会被触发。因为默认的那些异常都有特定的触发条件,例如:索引不存在、键不存在会触发IndexError和KeyError异常。

对于我们自定义的异常,如果想要触发,则需要使用:raise MyException()类实现。

class MyException(Exception):passtry:# 。。。raise MyException()# 。。。
except MyException as e:print("MyException异常被触发了", e)
except Exception as e:print("Exception", e)

class MyException(Exception):def __init__(self, msg, *args, **kwargs):super().__init__(*args, **kwargs)self.msg = msgtry:raise MyException("xxx失败了")
except MyException as e:print("MyException异常被触发了", e.msg)
except Exception as e:print("Exception", e)

class MyException(Exception):title = "请求错误"try:raise MyException()
except MyException as e:print("MyException异常被触发了", e.title)
except Exception as e:print("Exception", e)

3.3.3. 特殊的finally

try:# 逻辑代码
except Exception as e:# try中的代码如果有异常,则此代码块中的代码会执行。
finally:# try中的代码无论是否报错,finally中的代码都会执行,一般用于释放资源。print("end")

当在函数或方法中定义异常处理的代码时,要特别注意finally和return。

def func():try:return 123except Exception as e:passfinally:print(666)func()

在try或except中即使定义了return,也会执行最后的finally块中的代码。

3.4. 反射

反射,提供了一种更加灵活的方式让你可以实现去 对象 中操作成员(以字符串的形式去 对象 中进行成员的操作)。

Python中提供了4个内置函数来支持反射:

  • getattr,去对象中获取成员
v1 = getattr(对象,"成员名称")
v2 = getattr(对象,"成员名称", 不存在时的默认值)

  • setattr,去对象中设置成员
setattr(对象,"成员名称",值)

  • hasattr,对象中是否包含成员
v1 = hasattr(对象,"成员名称") # True/False

  • delattr,删除对象中的成员
delattr(对象,"成员名称")

以后如果再遇到 对象.成员 这种编写方式时,均可以基于反射来实现。

案例:

class Account(object):def login(self):passdef register(self):passdef index(self):passdef run(self):name = input("请输入要执行的方法名称:") # index register login xx run ..account_object = Account()method = getattr(account_object, name,None) # index = getattr(account_object,"index")if not method:print("输入错误")return method()

3.4.1. 一些皆对象

在Python中有这么句话:万事万物,一切皆对象。 每个对象的内部都有自己维护的成员。

  • 对象是对象
class Person(object):def __init__(self,name,wx):self.name = nameself.wx = wxdef show(self):message = "姓名{},微信:{}".format(self.name,self.wx)user_object = Person("jiaoxingk","jiaoxingk666")
user_object.name

  • 类是对象
class Person(object):title = "jiaoxingk"Person.title
# Person类也是一个对象(平时不这么称呼)

  • 模块是对象
import rere.match
# re模块也是一个对象(平时不这么称呼)。

由于反射支持以字符串的形式去对象中操作成员【等价于 对象.成员 】,所以,基于反射也可以对类、模块中的成员进行操作。

简单粗暴:只要看到 xx.oo 都可以用反射实现。

class Person(object):title = "jiaoxingk"v1 = Person.title
print(v1)
v2 = getattr(Person,"title")
print(v2)

import rev1 = re.match("\w+","dfjksdufjksd")
print(v1)func = getattr(re,"match")
v2 = func("\w+","dfjksdufjksd")
print(v2)

3.4.2. import_module + 反射

在Python中如果想要导入一个模块,可以通过import语法导入;企业也可以通过字符串的形式导入。

示例一:

# 导入模块
import randomv1 = random.randint(1,100)

# 导入模块
from importlib import import_modulem = import_module("random")v1 = m.randint(1,100)

示例二:

# 导入模块exceptions
from requests import exceptions as m

# 导入模块exceptions
from importlib import import_module
m = import_module("requests.exceptions")

在很多项目的源码中都会有 import_modulegetattr 配合实现根据字符串的形式导入模块并获取成员

我们在开发中也可以基于这个来进行开发,提高代码的可扩展性

结尾

至此,面向对象篇就完结啦,虽然有很多小细节没有写的很到位,后续也会慢慢补充。学完面向对象,就可以自己动手写一个小项目咯。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

第十四章[面向对象]:14.8:枚举类

一,定义枚举类 1,把一个类定义为枚举类: 只需要让它继承自 enum 模块中的 Enum 类即可。 例如在下面的例子中,Weekday 类继承自 Enum 类, 则表明这是一个枚举类 枚举类的每个成员都由 2 部分组成,分别是 name 和 value, 其中 name 属性值为该枚举值的变量名(如下例中: …

微信小程序 ---- 生命周期

目录 生命周期 1. 小程序运行机制 2. 小程序更新机制 3. 生命周期介绍 4. 应用级别生命周期 5. 页面级别生命周期 6. 生命周期两个细节补充说明 7. 组件生命周期 总结 生命周期 1. 小程序运行机制 冷启动与热启动&#xff1a; 小程序启动可以分为两种情况&#xff0…

flutter插件开发基础教程

前言 虽然现在已经有很多插件了&#xff0c;但是有时候还是需要自己开发一个插件。因此打算学习一下如何开发一个插件。这里只考虑安卓&#xff0c;安卓使用kotlin&#xff0c;kotlin不会也没事&#xff0c;我也不会。 参考项目&#xff1a;https://github.com/TBoyLi/flutte…

【更换yarn的位置】解决yarn和nodejs不在同一盘下产生的某些命令应用失败问题

具体问题我记得是command fail什么error&#xff0c;记不太清楚了&#xff0c;文章主要写了如何替换yarn路径&#xff0c;希望可以帮助到大家。

【YOLO系列算法人员摔倒检测】

YOLO系列算法人员摔倒检测 模型和数据集下载YOLO系列算法的人员摔倒检测数据集可视化数据集图像示例&#xff1a; 模型和数据集下载 yolo行人跌倒检测一&#xff1a; 1、训练好的行人跌倒检测权重以及PR曲线&#xff0c;loss曲线等等&#xff0c;map达90%多&#xff0c;在行人跌…

测试需求平台7-产品管理服务接口一篇搞定

✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版&#xff0c;拥抱Vue3.0将前端框架替换成字节最新开源的arco.design&#xff0c;其中约60%重构和20%新增内容&#xff0c;定位为从 0-1手把手实现简单的测试平台开发教程&#xff0c;内容将囊括基础、扩展和实战&a…

VSCode中打开md文件的智能提示

VSCode中打开md文件的智能提示 vscode中md的只能提示是默认关闭的,要打开必须要做些设置. 搜了好多文章,都是坑! 明明没设置成功,参数类型不对还信誓旦旦的坑自己同胞! 也难怪国内人学的那么难,反而国外学的很简单! 找了以下外面的资料,还是隔壁的人认真,给出了以下方法,测试成…

《TCP/IP详解 卷一》第6章 DHCP

目录 6.1 引言 6.2 DHCP 6.2.1 地址池和租用 6.2.2 DHCP和BOOTP消息格式 6.2.3 DHCP和BOOTP选项 6.2.4 DHCP协议操作 6.2.5 DHCPv6 6.2.6 DCHP中继 6.2.7 DHCP认证 6.2.8 重新配置扩展 6.2.9 快速确认 6.2.10 位置信息&#xff08;LCI和LoST&#xff09; 6.2.11 移…

OpenCV 4基础篇| OpenCV像素的编辑

目录 1. 前言1. 像素的访问1.1 数组索引访问1.2 img.item() 2. 像素的修改2.1 数值索引修改2.2 img.itemset() 1. 前言 像素是构成数字图像的基本单位&#xff0c;像素处理是图像处理的基本操作。 对像素的访问、修改&#xff0c;可以使用 Numpy 方法直接访问数组元素。 1. 像…

备考2024年AMC10:2000-2023年1250道AMC10真题练一练

我整理了2000-2023年的全部AMC10的AB卷真题共1250题&#xff0c;并且独家制作了多种在线练习&#xff0c;利用碎片化时间&#xff0c;一年足以通过自学在2024年AMC10竞赛中取得好成绩。 我们今天继续来随机看五道题目和解析。 2000-2023年AMC10真题练一练&#xff1a;2013年第…

洛谷P8627 [蓝桥杯 2015 省 A] 饮料换购

#先看题目 题目描述 乐羊羊饮料厂正在举办一次促销优惠活动。乐羊羊 C 型饮料&#xff0c;凭 3 个瓶盖可以再换一瓶 C 型饮料&#xff0c;并且可以一直循环下去(但不允许暂借或赊账)。 请你计算一下&#xff0c;如果小明不浪费瓶盖&#xff0c;尽量地参加活动&#xff0c;那…

Python入门学习——基础语法

一、Python解释器 1. Python解释器的作用是&#xff1a; 将Python代码翻译成计算机认识的O和1并提交计算机执行在解释器环境内可以一行行的执行我们输入的代码也可以使用解释器程序&#xff0c;去执行".py"代码文件 2. Python解释器程序在&#xff1a; <Python…

【第七天】C++模板探秘:函数模板、类模板以及类型转换的深入解析

一、模板的概述 c面向对象编程思想&#xff1a;封装、继承、多态 c泛型编程思想&#xff1a;模板 模板的分类&#xff1a;函数模板、类模板 函数模板&#xff08;类模板&#xff09;&#xff1a;将功能相同&#xff0c;类型不同的函数&#xff08;类&#xff09;的类型抽象成虚…

QoS 服务质量

服务质量 QoS (Quality of Service) 服务质量可用若干基本性能指标来描述&#xff0c;包括&#xff1a;可用性、差错率、响应时间、吞吐量、分组丢失率、连接建立时间、故障检测和改正时间等。 服务提供者可向其用户保证某一种等级的服务质量。 服务性能的总效果&#xff0c;…

svn客户端下载、安装、使用

下载、使用 打开360软件管家&#xff0c;选怎宝库&#xff0c;搜索svn&#xff0c;点击安装 可以修改安装路径 使用 在桌面右键弹出菜单&#xff0c;点击 输入地址&#xff0c;点击ok 输入用户名、密码 &#xff0c;等待检出完成

手把手教你安装和激活Fl Studio21.2.3.4004破解补丁(附激活教程)

盼望着盼望着&#xff0c;FL Studio21带这它的版本号2.3.4004来了&#xff0c;是最新版Fl Studio21.2.3.4004 关于FL Studio21.2.3.4004破解激活&#xff0c;跟之前版本一样&#xff0c;这篇文章将给大家带来FL Studio 21.2.3.400彻底激活教程&#xff0c;喜欢的朋友欢迎一键3连…

第八篇【传奇开心果系列】python的文本和语音相互转换库技术点案例示例:Google Text-to-Speech虚拟现实(VR)沉浸式体验经典案例

传奇开心果博文系列 系列博文目录python的文本和语音相互转换库技术点案例示例系列 博文目录前言一、雏形示例代码二、扩展思路介绍三、虚拟导游示例代码四、交互式学习示例代码五、虚拟角色对话示例代码六、辅助用户界面示例代码七、实时语音交互示例代码八、多语言支持示例代…

守护进程出现拉起多个子进程问题

引言 在我自己开发的httpApi进程中&#xff0c;使用了守护进程&#xff0c;保证进程在意外退出的时候可以重新自动启动。但是使用pstree的时候发现创建了不止一个进程&#xff0c;其中代码和问题现象如下&#xff1a; 代码 int main(int argc, char *argv[]) {printMainVer()…

计算机网络-网络层,运输层,应用层

网络层/网际层 网络层的主要任务包括&#xff1a; 提供逻辑上的端到端通信&#xff1a;网络层负责确定数据的传输路径&#xff0c;使数据能够从源主机传输到目标主机&#xff0c;即实现端到端的通信。数据包的路由和转发&#xff1a;网络层根据目标主机的地址信息&#xff0c…

MySQL事务(基础入门)(高频考点)

文章目录 前言什么是事务&#xff1f;事务的特性并发情况下会出现哪些问题脏读不可重复读幻读 总结 前言 今天来讲一讲 MySQL 事务的基础入门。 更多关于MySQL的知识可以看此专栏 MySQL专栏&#xff08;持续更新&#xff09; 什么是事务&#xff1f; 当我们在操作数据库的时…