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

news2024/11/17 13:34:04

目录

引言

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):
    pass

class 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):
    pass


class C(D):
    pass


class B(D):
    pass


class A(B, C):
    pass


print(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):
    pass

class Foo(Base):
    pass

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

Py2:

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

class Foo(Base):
  pass

Py3

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

class Bar(object):
    pass

3.3. 异常处理

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

import requests

while 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 requests

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

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

import requests
from requests import exceptions

while 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:
    # 逻辑代码
    pass

except 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):
    pass


try:
    # 。。。
    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 = msg


try:
    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 123
    except Exception as e:
        pass
    finally:
        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):
        pass

    def register(self):
        pass

    def index(self):
        pass

    
def 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 = name
        self.wx = wx
	
    def 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 re

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

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

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

class Person(object):
    title = "jiaoxingk"

v1 = Person.title
print(v1)
v2 = getattr(Person,"title")
print(v2)

import re

v1 = re.match("\w+","dfjksdufjksd")
print(v1)

func = getattr(re,"match")
v2 = func("\w+","dfjksdufjksd")
print(v2)

3.4.2. import_module + 反射

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

示例一:

# 导入模块
import random

v1 = random.randint(1,100)

# 导入模块
from importlib import import_module

m = 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.coloradmin.cn/o/1467270.html

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

相关文章

document.cookie中expires 格式设置问题导致部分iphone safari上登录失效

一、问题描述 设备信息&#xff1a;iPhone 12, iOS 16.3 昨天有个小伙伴发现自己的iPhone safari打开网页登录时&#xff0c;登录页面显示登录成功&#xff0c;但实际进入首页后仍然显示未登录。多次测试&#xff0c;该问题在该设备上属于必现问题。 二、问题排查与解决 经过…

蓝桥杯:真题讲解2(C++版)附带解析

星系炸弹 来自&#xff1a;2015年六届省赛大学B组真题&#xff08;共6道题) 分析&#xff1a;这题涉及到平年和闰年的知识&#xff0c;如果我们要解这题&#xff0c;首先要知道每月有多少天&#xff0c;其实也就是看2月份的天数&#xff0c;其它月份的天数都是一样的&#xff…

【开源】JAVA+Vue.js实现校园电商物流云平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 商品数据模块2.3 快递公司模块2.4 物流订单模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 商品表3.2.2 快递公司表3.2.3 物流订单表 四、系统展示五、核心代码5.1 查询商品5.2 查询快递公司5.3 查…

多人协作记账账本小程序开源版开发

多人协作记账账本小程序开源版开发 支持多人协作的记账本小程序&#xff0c;可用于家庭&#xff0c;团队&#xff0c;组织以及个人的日常收支情况记录&#xff0c;支持周月年度统计 便捷记账 便捷的记账方式&#xff0c;支持多种记账类型&#xff0c;快捷切换账本等 多账本 支…

如何使用ChatGPT创建一份优质简历

目录 第一步&#xff1a;明确目标和重点 第二步&#xff1a;与ChatGPT建立对话 第三步&#xff1a;整理生成的内容 第四步&#xff1a;注重行文风格 第五步&#xff1a;强调成就和量化结果 第六步&#xff1a;个性化和定制 第七步&#xff1a;反复修改和完善 总结 在现…

MATLAB:数组与矩阵

2.1 数组运算 数组运算时MATLAB计算的基础。由于MATLAB面向对象的特性&#xff0c;这种数值数组称为MATLAN最重要的一种内建数据类型&#xff0c;而数组运算就是定义这种数据结果的方法。 2.1.1 数组的创建和操作 在MATLAB中一般使用方括号“[]”、逗号“,”、空格和分号“;…

Frp 内网穿透服务器基于Docker+Nginx搭建 保姆间级别最细教程

Frp 内网穿透服务器基于DockerNginx搭建 前言介绍 ​ 原先使用的内网穿透服务&#xff0c;natapp、花生壳等三方内网穿透服务&#xff0c;特点方便&#xff0c;但是条数少&#xff0c;有带宽限制&#xff0c;还要实名认证。过于麻烦&#xff0c;自己准备搭建Frp个人穿透服务器…

计算机网络实验八 利用 Java /C++开发网络聊天应用程序

一、实验目的和要求 1)基本掌握利用 Java 开发环境调试应用程序的方法。 2)理解基于套接字开发网络应用程序的过程,深入理解客户/服务器方式工作原理。 3)掌握基于Java和C++开发网络通信程序的方法。 二、实验环境 1)运行 Windows 2008 Server/XP/7 操作系统的 PC 2 台…

python统计分析——线性模型的预测和评估

参考资料&#xff1a;用python动手学统计学 1、导入库 # 导入库 # 导入数据处理的库 import numpy as np import pandas as pd import scipy as sp from scipy import stats # 导入绘图的库 from matplotlib import pyplot as plt import seaborn as sns sns.set() # 导入估计…

更简单地介绍 CUDA

这篇文章是对 CUDA 的超级简单介绍&#xff0c;CUDA 是 NVIDIA 流行的并行计算平台和编程模型。我之前在2013年写过一篇文章《CUDA简单介绍》&#xff0c;多年来一直很受欢迎。但 CUDA 编程变得更加容易&#xff0c;GPU 也变得更快&#xff0c;所以是时候进行更新&#xff08;甚…

【Java程序设计】【C00290】基于Springboot的网上书城管理系统(有论文)

基于Springboot的网上书城管理系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的网上书城管理系统 本系统分为系统功能模块、管理员功能模块以及用户功能模块。 系统功能模块&#xff1a;在系统首页可以查看首…

Atcoder ABC340 A-D题解

比赛链接:ABC340 话不多说&#xff0c;看题。 Problem A: 签到。 #include <bits/stdc.h> using namespace std; int main(){int a,b,d;cin>>a>>b>>d;for(int ia;i<b;id)cout<<i<<endl;return 0; } Problem B: 还是签到题。一个v…

潇洒郎:2024 IDEA、Pycharm获取最新激活码获取方式

IDEA获取最新激活码 https://idea.javatiku.cn/ 手机打开&#xff0c;看到验证码&#xff0c;30分钟有效&#xff0c;输入验证码 获取到最新激活码

挑战杯 基于大数据的社交平台数据爬虫舆情分析可视化系统

文章目录 0 前言1 课题背景2 实现效果**实现功能****可视化统计****web模块界面展示**3 LDA模型 4 情感分析方法**预处理**特征提取特征选择分类器选择实验 5 部分核心代码6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于大数据…

使用Python制作进度条有多少种方法?看这一篇文章就够了!

前言 偶然间刷到一个视频&#xff0c;说到&#xff1a;当程序正在运算时&#xff0c;会有一个较长时间的空白期&#xff0c;谁也不知道程序运行的进度如何&#xff0c;不如给他加个进度条。 于是我今个就搜寻一下&#xff0c;Python版的进度条都可以怎么写&#xff01; 送书…

展望2024生物发酵领域-振华仪表

参展企业介绍 杭州振华仪表有限公司(简称“振华仪表”)是集电磁流量计研发、生产、销售、服务于一体的国家高新技术企业、省“专精特新”企业&#xff0c;主导起草了《电磁流量计检定规程(JJG 1033—2007)》、《智能变送器性能评定方法》等4项国家标准。 振华仪表于1985年成功…

[已解决]npm淘宝镜像最新官方指引(2023.08.31)

最新的配置淘宝镜像的淘宝官方提供的方法 npm config set registry https://registry.npmmirror.com原来的 registry.npm.taobao.org 已替换为 registry.npmmirror.com &#xff0c;当点击 registry.npm.taobao.org 会默认跳转到 registry.npmmirror.com 如果你想将npm的下载…

小保司的理赔是否有保障?

《小保司的理赔是否有保障&#xff1f;》 预计6-7分钟读完 连续日更&#xff1a;第7天 作者&#xff1a;罗师兄 微信号&#xff1a;luoyun515 同一个人&#xff0c;同样的重疾险责任&#xff0c; 同样的保额&#xff0c;同样的缴费方式&#xff0c; 不同的保司保费可以相…

一文看懂大模型 Sora 技术推演

sora 一出&#xff0c;引起社会各界广泛关注。中美AI的差距进一步扩大&#xff0c;中美人才培养体系的差距等等言论&#xff0c;甚嚣尘上。 其实文生视频领域&#xff0c;华人学者和产业界的参与度还是非常高的。 那么 Sora 到底是谁做的&#xff0c;怎么做的&#xff0c;本篇…

2024年 最新python调用ChatGPT实战教程

2024年 最新python调用ChatGPT实战教程 文章目录 2024年 最新python调用ChatGPT实战教程一、前言二、具体分析1、简版程序2、多轮对话3、流式输出4、返回消耗的token 一、前言 这个之前经常用到&#xff0c;简单记录一下,注意目前chatgpt 更新了&#xff0c;这个是最新版的&am…