跟着我学Python进阶篇:04. 错误和异常

往期文章

跟着我学Python基础篇:01.初露端倪
跟着我学Python基础篇:02.数字与字符串编程
跟着我学Python基础篇:03.选择结构
跟着我学Python基础篇:04.循环
跟着我学Python基础篇:05.函数
跟着我学Python基础篇:06.列表
跟着我学Python基础篇:07.文本
跟着我学Python基础篇:08.集合和字典


跟着我学Python进阶篇:01.试用Python完成一些简单问题
跟着我学Python进阶篇:02.面向对象(上)
跟着我学Python进阶篇:03.面向对象(下)


目录

  • 往期文章
  • 1. 错误和异常的简介
    • 1.1 异常
    • 1.2 Python常见异常
  • 2. 捕获异常
    • 2.1 try-expect语句
    • 2.2 获取异常提示信息
    • 2.3 捕获多个异常
    • 2.4 捕获所有异常
    • 2.5 else语句
    • 2.6 finally语句
  • 3. 抛出异常
    • 3.1 raise语句
    • 3.2 异常的传递
    • 3.3 assert断言语句
  • 4. 自定义异常
  • 5. with语句处理异常
    • 5.1 with语句
    • 5.2 上下文管理器
    • 5.3 自定义上下文管理器

1. 错误和异常的简介

程序中的错误分为逻辑错误和语法错误,语法错误是指软件的编写不符合Python语言的语法规定,导致无法被解释器解释或者编译器编译。这些错误必须修正,程序才能运行。语法错误的类型是SyntaxError。程序运行以后出现的错误是逻辑错误,逻辑错误可能是由于外界条件允许的,也可能是程序本身设计不严谨导致的。不管哪种错误,只要被Python检测到,都会发生异常。

1.1 异常

在程序运行期间检测到的错误称之为异常,如果异常不被处理,默认的方式是程序崩溃,并给出错误提示。

1.2 Python常见异常

AttributeError:尝试访问未定义的属性或方法时引发的异常。
FileNotFoundError:尝试打开不存在的文件时引发的异常。
IndexError:尝试访问列表、元组或字符串中不存在的索引时引发的异常。
KeyError:尝试访问字典中不存在的键时引发的异常。
NameError:尝试访问未声明或未初始化的变量时引发的异常。
TypeError:操作或函数应用于不适当类型的对象时引发的异常。
ValueError:传递给函数的参数具有正确的类型,但具有不合适的值时引发的异常。
ZeroDivisionError:除以零时引发的异常。

2. 捕获异常

Python中使用try-expect语句处理异常,其中try语句检测异常,except语句捕获异常。

2.1 try-expect语句

在这里插入图片描述

首先,“try” 块中的代码会被执行。这是可能引发异常的代码块。
如果在 “try” 块中的代码执行期间没有发生任何异常,那么 “except” 块将被跳过,程序将继续执行后续的代码。
如果在 “try” 块中的代码执行期间引发了一个异常,那么与该异常类型匹配的第一个 “except” 块将被执行。如果有多个 “except” 块,并且匹配多个异常类型,只有第一个匹配的块将被执行,其他的块将被忽略。
异常被捕获后,与异常相关的 “except” 块中的代码将被执行。这是你可以在其中处理和恢复异常的地方。
如果没有与异常类型匹配的 “except” 块,或者异常类型没有被指定,那么该异常将传递给上一层的调用堆栈,直到找到能够处理该异常的 “except” 块或者程序终止。

2.2 获取异常提示信息

有些异常可以在程序中纠正,有些不能。一般程序中会维护一个日志,记录程序中出现的所有异常,此时可以使用as获取系统反馈的具体信息。

例如:

try:print("我的年龄是"+18)print("我叫富豪")
except TypeError as error:print("错误信息:")print(error)

在这里插入图片描述

2.3 捕获多个异常

一个代码可能出现多个异常,可以将多个特定异常组成一个元祖放在一个except语句后处理,也可以多个except字句联合使用。

try:print(abc)print(2/0)
except(NameError,ZeroDivisionError) as error:print(error)

在这里插入图片描述
同时捕获多个异常,只能使用一种方式进行处理,如果希望对不同的异常采用不同的处理方式,可以使用多个except字句,可以使用下面的写法:

try:print(2/0)print(abc)
except NameError as error:print(error)
except ZeroDivisionError:print("不能使用0作为除数")

注:Python2中把多个异常用逗号隔开,Python3需要将多个异常元祖组织起来,也就是多个圆括号。

2.4 捕获所有异常

在Python中捕获所有异常有两种方式,一种使用Exception,由于Exception是所有异常的基类,所以可以包含所有异常。

try:demo_list=[1,2,3,4]print(demo_list[5])
except Exception as error:print(error)print("错误")

在这里插入图片描述
另一种方式是使用except,如:

try:demo_list=[1,2,3,4]print(demo_list[5])
except:print("错误")

在这里插入图片描述
在except后缺异常类型,也会将所有异常都捕获。不过这种方式并不推荐,一是不能获取错误的具体信息,二是它还会捕获我们并不想捕获的异常,比如用户终止执行的Ctrl C操作,以及用sys.exit()函数程序终止操作。

异常处理的主要目的是防止因外部环境变化导致程序无法控制的错误,而不应该用于处理程序设计错误,将所有代码用try语句包含是不正确的。
捕获异常之后要进行相应的处理,如果异常之后用pass直接忽略掉,会隐藏掉程序出错的原因,不利于程序的运行和维护,也是不推荐的。

2.5 else语句

else语句可以和try-expect配合使用:
try:
可能会引发异常的代码块

except ExceptionType1:
处理 ExceptionType1 类型的异常的代码块

except ExceptionType2:
处理 ExceptionType2 类型的异常的代码块

else:
没有发生异常时执行的代码块

2.6 finally语句

finally语句与try语句联合使用,表示无论try语句是否出错都会执行语句。
try:
# 可能会引发异常的代码块
# …
finally:
# 无论是否发生异常,都会执行的代码块
# …

3. 抛出异常

如果捕获到的异常在本级无法处理,或者不应由本级处理,也可以将异常抛出,交给上一级代码处理。

3.1 raise语句

raise语句用于抛出特定的异常。

  1. 创建类的实例对象,引发异常:
    raise 异常类名
  2. 引发异常实例对象对应的异常
    raise 异常类实例对象
  3. 重新引发刚才发生的异常
    raise

在上述格式中,第一种和第二种是对等的,都会引发指定异常类的实例,但是第一种形式隐式地创建了异常类的实例,而第二种形式是最常见的,直接提供一个实例,第三种用于重新引发刚刚发生的异常。

下面通过实例来对raise语句进行介绍:

  1. 使用类名引发异常

当raise语句指定异常类名时,会创建该类的实例对象,然后引发异常。

raise IndexError

在这里插入图片描述

  1. 使用异常类的实例引发异常
    通过显式地创建异常类的实例,直接使用该实例对象来引发异常。
index=IndexError()
raise index

在这里插入图片描述

  1. 传递异常
    不带任何参数的raise语句,可以再次引发刚刚发生过的异常,作用就是向外传递异常。
try:raise IndexError
except:print("出错了")raise

在这里插入图片描述

  1. 指定异常的描述信息
    当使用raise语句抛出异常时,还能给异常类指定描述信息。
raise IndexError("索引超出下标范围")

在这里插入图片描述

  1. 异常引发异常
    如果要在异常中抛出另一个异常,可以使用raise from语句实现。

在这里插入图片描述

3.2 异常的传递

如果异常没有被处理,默认情况将会上传给上层代码,逐级向上传递,如果最上层的代码没有处理,则会使用系统默认方式。

3.3 assert断言语句

assert语句是一种用于调试和测试的Python语句。它用于检查一个条件是否为真,如果为假,则会引发一个AssertionError异常。

assert语句的语法如下:
assert condition, message

4. 自定义异常

自定义异常类需要创建一个类,让他继承自Exception类或其子类即可。

class MyCustomException(Exception):def __init__(self, message):super().__init__(message)self.error_code = 100def log_error(self):# 自定义异常类的方法print("Logging error: ", self.__str__())try:raise MyCustomException("Something went wrong!")
except MyCustomException as e:print("Exception occurred:", e)e.log_error()

5. with语句处理异常

with语句支持创建资源、抛出异常、释放资源等操作。

5.1 with语句

with语句适用于对资源进行访问的场合,无论资源使用过程中是否发生异常,都会执行必要的释放资源的操作。比如文件使用后自动关闭,线程中锁的自动获取和释放。
with语句的语法格式如下:
with 上下文表达式 [as 资源对象]:
对对象的操作

上下文表达式返回一个上下文管理对象,如果指定as子句,该对象并不赋值给as子句中的资源对象,而是将上下文管理器的_enter()_方法赋值给资源对象,资源对象可以是单个变量也可以是元祖。

例如,对with语句操作文件对象的示例如下:

with open(‘test.txt’) as file:
for aline in file:
print(aline)

with语句从Python2.5 开始引入(需通过from_future_import with_statement导入),从Python2.6开始可以缺省。

不是所有对象都可以使用with语句,只有支持上下文管理协议的对象才可以。

5.2 上下文管理器

上下文管理协议与with有关的概念包括:

  1. 上下文管理协议(Context Management Protocal)
    enter(): 当进入with语句块时,会调用该方法。它负责返回一个值,通常是对象本身或与上下文相关的资源。
    exit(exc_type, exc_value, traceback): 当离开with语句块时,无论是正常离开还是发生异常,都会调用该方法。它负责处理上下文退出时的清理工作,关闭资源等。

  2. 上下文管理器
    支持上下文管理协议的对象就是上下文管理器,这种对象实现了_enter_()和_exit_()方法,使用with语句即可调用上下文管理器,它负责建立运行时上下文。

  3. 运行时上下文
    由上下文管理器创建,通过上下文管理器的_enter_()和_exit_()方法实现。

  4. 上下文表达式
    with语句在with关键字后出现的表达式,该表达式要返回一个支持上下文管理协议的对象,也就是返回一个上下文管理器。

  5. 语句体
    由with语句包括起来的包括块,表示对资源对象的操作。在执行语句之前会执行上下文管理器的_enter_()方法,执行之后调用_exit_()方法。

了解了上下文管理器就理解了with语句执行过程了:

当执行到with语句时,首先调用上下文管理器对象的_enter_()方法,该方法负责获取资源并返回一个值。
进入with语句块,执行其中的代码。
如果在with语句块中发生异常,异常会被捕获。
无论是否发生异常,都会调用上下文管理器对象的_exit_(exc_type, exc_value, traceback)方法。如果没有发生异常,这三个参数都是None;如果有异常,这三个参数分别表示异常类型、异常实例和追溯信息。

5.3 自定义上下文管理器

要自定义上下文管理器,需要创建一个类并实现上下文管理协议的方法_enter_()和_exit_()。

class MyContext:def __enter__(self):print("Entering context")# 返回要在上下文中使用的对象或资源return "Hello, world!"def __exit__(self, exc_type, exc_value, traceback):print("Exiting context")# 处理上下文退出时的清理工作if exc_type:print("Exception occurred:", exc_type, exc_value)# 使用自定义的上下文管理器
with MyContext() as context:print(context)# 在上下文中执行一些操作# 上下文外部继续执行其他代码
print("Outside context")

在上面的例子中,我们定义了一个名为MyContext的上下文管理器类。它实现了__enter_()和 exit()方法。

在_enter__()方法中,我们可以执行一些准备工作,并返回一个对象或资源,该对象或资源将在with语句块中使用。在这个示例中,我们返回了一个简单的字符串。

在_exit_()方法中,我们可以处理上下文退出时的清理工作,例如关闭文件、释放资源等。如果在with语句块中发生异常,异常信息会传递给_exit__()方法的参数。

然后,我们使用with语句创建了一个MyContext对象,并将其赋值给context变量。在`with语句块中,我们打印了context的值,并执行了一些操作。

当离开with语句块时,无论正常离开还是发生异常,都会自动调用_exit_()方法,进行清理工作。在这个示例中,我们打印了退出上下文的信息。

最后,在上下文外部继续执行其他代码,打印了"Outside context"。

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

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

相关文章

CSS之高度塌陷和外边距塌陷

目录 1.高度塌陷(原因,如何解决) 【概念介绍】 【解决办法】 【概念介绍-BFC】 【拓展-BFC的触发条件】 2.外边距塌陷 (原因,如何解决) 【概念介绍】 【两种情况】 1.相邻块元素 2.嵌套块元素 【…

PPP协议原理介绍+报文分析+配置指导-RFC1661

个人认为,理解报文就理解了协议。通过报文中的字段可以理解协议在交互过程中相关传递的信息,更加便于理解协议。 因此本文将在PPP协议报文的基础上进行介绍。 关于PPP协议基本原理,可参考RFC1661-The Point-to-Point Protocol (PPP)。 关于P…

编译原理2.3习题 语法制导分析[C++]

图源:文心一言 编译原理习题整理~🥝🥝 作为初学者的我,这些习题主要用于自我巩固。由于是自学,答案难免有误,非常欢迎各位小伙伴指正与讨论!👏💡 第1版:自…

Spring扩展点在微服务应用(待完善)

ApplicationListener扩展 nacos注册服务, 监听容器发布事件 # 容器发布事件 AbstractAutoServiceRegistration#onApplicationEvent # 接收事件吗,注册服务到nacos NacosServiceRegistry#register Lifecycle扩展 #订阅服务实例更改的事件 NamingService#…

go语言数组和切片

1. 数组Array Golang Array和以往认知的数组有很大不同。 1. 数组:是同一种数据类型的固定长度的序列。2. 数组定义:var a [len]int,比如:var a [5]int,数组长度必须是常量,且是类型的组成部分。一旦定义&…

设计模式: 装饰模式

文章目录 一、什么是装饰模式二、装饰模式的结构三、使用场景案例分析 一、什么是装饰模式 在不改变对象原有行为的基础上,动态的来为该对象绑定新的行为。 二、装饰模式的结构 装饰模式结构中主要包含如下角色: Component(抽象部件&…

操作系统-虚拟机(传统计算机 虚拟机 两类VMM对比 指令等级 特权与敏感)

文章目录 传统计算机虚拟机VMM的对比支持虚拟化的CPU通常分更多指令等级(特权 敏感) 传统计算机 传统物理机只有一个操作系统 两个进程在一个操作系统上运行会存在一些隐患(相互影响 争夺资源等) 解决方法:如果各个进…

Docker部署

Docker简介 Docker是一个开源的容器引擎,它有助于更快地交付应用。 Docker可将应用程序和基础设施层隔离,并且能将基础设施当作程序一样进行管理。使用 Docker可更快地打包、测试以及部署应用程序,并可以缩短从编写到部署运行代码的周期。 &a…

HCIP 交换

拓扑图&IP划分如下: 第一步,配制VLAN LSW1,LSW2&LSW3同理 检测 LSW1 LSW2 测试

硬件之相机选型

1. 相机成像原理 相机成像原理如图所示: 注: 当物距为无穷远时,像距等于焦距,成像在焦平面上;当物距为无穷无与两倍焦距之间时,像距在焦距与两倍焦距之间,成缩小的实像;当物距等于两…

MySQL的主从复制

主从复制是指将主数据库的 DDL 和 DML 操作通过二进制日志传到从库服务器中,然后在从库上对这些日志重新执行(也叫重做),从而使得从库和主库的数据保持同步。 MySQL支持一台主库同时向多台从库进行复制, 从库同时也可…

什么是JMeter?我们为什么要用JMeter做性能测试

什么是JMeter?我们为什么要用JMeter做性能测试 什么是JMeter?为什么选择JMeterJMeter的优点JMeter是如何工作的 什么是JMeter? Apache JMeter TM是纯Java开源软件,最初由Apache软件基金会的Stefano Mazzocchi开发,旨在…