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://www.hqwc.cn/news/488300.html

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

相关文章

UI风格汇:扁平化风格来龙去脉,特征与未来趋势

Hello&#xff0c;我是大千UI工场&#xff0c;设计风格是我们新开辟的栏目&#xff0c;主要讲解各类UI风格特征、辨识方法、应用场景、运用方法等&#xff0c;本次带来的扁平化风格的解读&#xff0c;有设计需求&#xff0c;我们也可以接单。 一、什么是扁平化风格 扁平化风格…

多窗口编程

六、多窗口编程 QMessageBox消息对话框&#xff08;掌握&#xff09; QMessageBox继承自QDialog&#xff0c;显示一个模态对话框。用于用户前台信息通知或询问用户问题&#xff0c;并接收问题答案。 QDialog的Qt源码中&#xff0c;派生类往往都是一些在特定场合下使用的预设好的…

MFC 多文档程序的基本编程

下载了一个openGL mfc的多文档程序,以此来学习mfc多文档模式的编程; 1 基本编程 它每次新建一个文档,会在窗口绘制一个三角形、一个矩形;如果没有了图形刷新一下; 先看一下为什么每次打开新文档会绘制图形; 生成工程之后主要有5个类,比单文档程序多了一个子框架类; 可…

分享数字孪生潭江流域建设与实践论文

数字孪生潭江流域建设 广东省水利厅 以支撑江门市沿线水工程精准联调联控&#xff0c;提升水旱灾害防御能力为首要任务&#xff0c;融合多信息源预报、GIS等技术&#xff0c;建立气象-水文-水动力集一体的复杂流域入库径流预报及其洪涝延伸预报模型平台&#xff0c;构建具有“…

H12-821_29

29.四台路由器运行IS-S且已经建立邻接关系,区域号和路由器的等级如图中标记,下列说法中正确的有? A.R2和R3都会产生ATT置位的Level-1的LSP B.R1没有R4产生的LSP,因此R1只能通过缺省路由和R4通信 C.R2和R3都会产生ATT置位的Leve1-2的LSP D.R2和R3互相学习缺省路由,该网络出现路…

Jmeter学习系列之六:阶梯加压线程组Stepping Thread Group详解

性能测试中,有时需要模拟一种实际生产中经常出现的情况,即:从某个值开始不断增加压力,直至达到某个值,然后持续运行一段时间。 在jmeter中,有这样一个插件,可以帮我们实现这个功能,这个插件就是:Stepping Thread Group 1、下载配置方法 1.1.下载配置 插件下载地址:…

六、回归与聚类算法 - 岭回归

目录 1、带有L2正则化的线性回归 - 岭回归 1.1 API 2、正则化程度的变化对结果的影响 3、波士顿房价预测 线性回归欠拟合与过拟合线性回归的改进 - 岭回归分类算法&#xff1a;逻辑回归模型保存与加载无监督学习&#xff1a;K-means算法 1、带有L2正则化的线性回归 - 岭回…

如何申请雨云官方免费SSL证书(自写)

上期讲到&#xff0c;我们介绍了什么是SSL&#xff0c;那么我们简单回顾一下并且介绍如何领取&#xff01; &#xff08;1&#xff09;信息保密&#xff0c;通过使用公开密钥和对称密钥技术以达到信息保密。SSL客户机和服务器之间的 所有业务都使用在SSL握手过程中建立的密钥…

代码随想录刷题笔记-Day23

1. 组合 77. 组合https://leetcode.cn/problems/combinations/ 给定两个整数 n 和 k&#xff0c;返回范围 [1, n] 中所有可能的 k 个数的组合。 你可以按 任何顺序 返回答案。 示例 1&#xff1a; 输入&#xff1a;n 4, k 2 输出&#xff1a; [[2,4],[3,4],[2,3],[1,2],…

【vue】provide/inject

provide/ inject这对选项需要一起使用&#xff0c;以允许一个祖先组件向其所有子孙后代注入一个依赖&#xff0c;不论组件层次有多深&#xff0c;并在起上下游关系成立的时间里始终生效。 通途点来讲可以用来实现隔代传值&#xff0c;传统的props只能父传子&#xff0c;而 prov…

【漏洞复现】大华DSS视频管理系统信息泄露漏洞

Nx01 产品简介 大华DSS数字监控系统是一个在通用安防视频监控系统基础上设计开发的系统&#xff0c;除了具有普通安防视频监控系统的实时监视、云台操作、录像回放、报警处理、设备治理等功能外&#xff0c;更注重用户使用的便利性。 Nx02 漏洞描述 大华DSS视频管理系统存在信…

数字孪生低代码平台盘点(一):厂家介绍

特别说明&#xff1a;本文根据网上资料搜集整理而成&#xff0c;排名不分先后&#xff0c;配图是为了更好地阅读体验&#xff0c;并非表明该图为该平台所生产。如有错误之处&#xff0c;请在评论区提出。 一、优锘ChartBuilder 优锘ChartBuilder是一款基于Web的数据可视化工具…