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

2024-02-25 13:44

本文主要是介绍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 配合实现根据字符串的形式导入模块并获取成员

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

结尾

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

这篇关于Python奇幻之旅(从入门到入狱高级篇)——面向对象进阶篇(下)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/745663

相关文章

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

Python设置Cookie永不超时的详细指南

《Python设置Cookie永不超时的详细指南》Cookie是一种存储在用户浏览器中的小型数据片段,用于记录用户的登录状态、偏好设置等信息,下面小编就来和大家详细讲讲Python如何设置Cookie... 目录一、Cookie的作用与重要性二、Cookie过期的原因三、实现Cookie永不超时的方法(一)

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

Python函数作用域示例详解

《Python函数作用域示例详解》本文介绍了Python中的LEGB作用域规则,详细解析了变量查找的四个层级,通过具体代码示例,展示了各层级的变量访问规则和特性,对python函数作用域相关知识感兴趣... 目录一、LEGB 规则二、作用域实例2.1 局部作用域(Local)2.2 闭包作用域(Enclos

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Python中win32包的安装及常见用途介绍

《Python中win32包的安装及常见用途介绍》在Windows环境下,PythonWin32模块通常随Python安装包一起安装,:本文主要介绍Python中win32包的安装及常见用途的相关... 目录前言主要组件安装方法常见用途1. 操作Windows注册表2. 操作Windows服务3. 窗口操作

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提