Python异常类型以及处理方法汇总


Posted in Python onJune 05, 2021

前言

调试Python程序时,经常会报出一些异常,异常的原因一方面可能是写程序时由于疏忽或者考虑不全造成了错误,这时就需要根据异常Traceback到出错点,进行分析改正;另一方面,有些异常是不可避免的,但我们可以对异常进行捕获处理,防止程序终止。

1 异常类型

1.1 Python内置异常

Python的异常处理能力是很强大的,它有很多内置异常,可向用户准确反馈出错信息。在Python中,异常也是对象,可对它进行操作。BaseException是所有内置异常的基类,但用户定义的类并不直接继承BaseException,所有的异常类都是从Exception继承,且都在exceptions模块中定义。Python自动将所有异常名称放在内建命名空间中,所以程序不必导入exceptions模块即可使用异常。一旦引发而且没有捕捉SystemExit异常,程序执行就会终止。如果交互式会话遇到一个未被捕捉的SystemExit异常,会话就会终止。

内置异常类的层次结构如下:

BaseException  # 所有异常的基类
 +-- SystemExit  # 解释器请求退出
 +-- KeyboardInterrupt  # 用户中断执行(通常是输入^C)
 +-- GeneratorExit  # 生成器(generator)发生异常来通知退出
 +-- Exception  # 常规异常的基类
      +-- StopIteration  # 迭代器没有更多的值
      +-- StopAsyncIteration  # 必须通过异步迭代器对象的__anext__()方法引发以停止迭代
      +-- ArithmeticError  # 各种算术错误引发的内置异常的基类
      |    +-- FloatingPointError  # 浮点计算错误
      |    +-- OverflowError  # 数值运算结果太大无法表示
      |    +-- ZeroDivisionError  # 除(或取模)零 (所有数据类型)
      +-- AssertionError  # 当assert语句失败时引发
      +-- AttributeError  # 属性引用或赋值失败
      +-- BufferError  # 无法执行与缓冲区相关的操作时引发
      +-- EOFError  # 当input()函数在没有读取任何数据的情况下达到文件结束条件(EOF)时引发
      +-- ImportError  # 导入模块/对象失败
      |    +-- ModuleNotFoundError  # 无法找到模块或在在sys.modules中找到None
      +-- LookupError  # 映射或序列上使用的键或索引无效时引发的异常的基类
      |    +-- IndexError  # 序列中没有此索引(index)
      |    +-- KeyError  # 映射中没有这个键
      +-- MemoryError  # 内存溢出错误(对于Python 解释器不是致命的)
      +-- NameError  # 未声明/初始化对象 (没有属性)
      |    +-- UnboundLocalError  # 访问未初始化的本地变量
      +-- OSError  # 操作系统错误,EnvironmentError,IOError,WindowsError,socket.error,select.error和mmap.error已合并到OSError中,构造函数可能返回子类
      |    +-- BlockingIOError  # 操作将阻塞对象(e.g. socket)设置为非阻塞操作
      |    +-- ChildProcessError  # 在子进程上的操作失败
      |    +-- ConnectionError  # 与连接相关的异常的基类
      |    |    +-- BrokenPipeError  # 另一端关闭时尝试写入管道或试图在已关闭写入的套接字上写入
      |    |    +-- ConnectionAbortedError  # 连接尝试被对等方中止
      |    |    +-- ConnectionRefusedError  # 连接尝试被对等方拒绝
      |    |    +-- ConnectionResetError    # 连接由对等方重置
      |    +-- FileExistsError  # 创建已存在的文件或目录
      |    +-- FileNotFoundError  # 请求不存在的文件或目录
      |    +-- InterruptedError  # 系统调用被输入信号中断
      |    +-- IsADirectoryError  # 在目录上请求文件操作(例如 os.remove())
      |    +-- NotADirectoryError  # 在不是目录的事物上请求目录操作(例如 os.listdir())
      |    +-- PermissionError  # 尝试在没有足够访问权限的情况下运行操作
      |    +-- ProcessLookupError  # 给定进程不存在
      |    +-- TimeoutError  # 系统函数在系统级别超时
      +-- ReferenceError  # weakref.proxy()函数创建的弱引用试图访问已经垃圾回收了的对象
      +-- RuntimeError  # 在检测到不属于任何其他类别的错误时触发
      |    +-- NotImplementedError  # 在用户定义的基类中,抽象方法要求派生类重写该方法或者正在开发的类指示仍然需要添加实际实现
      |    +-- RecursionError  # 解释器检测到超出最大递归深度
      +-- SyntaxError  # Python 语法错误
      |    +-- IndentationError  # 缩进错误
      |         +-- TabError  # Tab和空格混用
      +-- SystemError  # 解释器发现内部错误
      +-- TypeError  # 操作或函数应用于不适当类型的对象
      +-- ValueError  # 操作或函数接收到具有正确类型但值不合适的参数
      |    +-- UnicodeError  # 发生与Unicode相关的编码或解码错误
      |         +-- UnicodeDecodeError  # Unicode解码错误
      |         +-- UnicodeEncodeError  # Unicode编码错误
      |         +-- UnicodeTranslateError  # Unicode转码错误
      +-- Warning  # 警告的基类
           +-- DeprecationWarning  # 有关已弃用功能的警告的基类
           +-- PendingDeprecationWarning  # 有关不推荐使用功能的警告的基类
           +-- RuntimeWarning  # 有关可疑的运行时行为的警告的基类
           +-- SyntaxWarning  # 关于可疑语法警告的基类
           +-- UserWarning  # 用户代码生成警告的基类
           +-- FutureWarning  # 有关已弃用功能的警告的基类
           +-- ImportWarning  # 关于模块导入时可能出错的警告的基类
           +-- UnicodeWarning  # 与Unicode相关的警告的基类
           +-- BytesWarning  # 与bytes和bytearray相关的警告的基类
           +-- ResourceWarning  # 与资源使用相关的警告的基类。被默认警告过滤器忽略。

详细说明请参考:https://docs.python.org/3/library/exceptions.html#base-classes

1.2 requests模块的相关异常

在做爬虫时,requests是一个十分好用的模块,所以我们在这里专门探讨一下requests模块相关的异常。

要调用requests模块的内置异常,只要“from requests.exceptions import xxx”就可以了,比如:

from requests.exceptions import ConnectionError, ReadTimeout

或者直接这样也是可以的:

from requests import ConnectionError, ReadTimeout

requests模块内置异常类的层次结构如下:

IOError
 +-- RequestException  # 处理不确定的异常请求
      +-- HTTPError  # HTTP错误
      +-- ConnectionError  # 连接错误
      |    +-- ProxyError  # 代理错误
      |    +-- SSLError  # SSL错误
      |    +-- ConnectTimeout(+-- Timeout)  # (双重继承,下同)尝试连接到远程服务器时请求超时,产生此错误的请求可以安全地重试。
      +-- Timeout  # 请求超时
      |    +-- ReadTimeout  # 服务器未在指定的时间内发送任何数据
      +-- URLRequired  # 发出请求需要有效的URL
      +-- TooManyRedirects  # 重定向太多
      +-- MissingSchema(+-- ValueError) # 缺少URL架构(例如http或https)
      +-- InvalidSchema(+-- ValueError) # 无效的架构,有效架构请参见defaults.py
      +-- InvalidURL(+-- ValueError)  # 无效的URL
      |    +-- InvalidProxyURL  # 无效的代理URL
      +-- InvalidHeader(+-- ValueError)  # 无效的Header
      +-- ChunkedEncodingError  # 服务器声明了chunked编码但发送了一个无效的chunk
      +-- ContentDecodingError(+-- BaseHTTPError)  # 无法解码响应内容
      +-- StreamConsumedError(+-- TypeError)  # 此响应的内容已被使用
      +-- RetryError  # 自定义重试逻辑失败
      +-- UnrewindableBodyError  # 尝试倒回正文时,请求遇到错误
      +-- FileModeWarning(+-- DeprecationWarning)  # 文件以文本模式打开,但Requests确定其二进制长度
      +-- RequestsDependencyWarning  # 导入的依赖项与预期的版本范围不匹配
 
Warning
 +-- RequestsWarning  # 请求的基本警告 

详细说明及源码请参考:http://www.python-requests.org/en/master/_modules/requests/exceptions/#RequestException

下面是一个简单的小例子,python内置了一个ConnectionError异常,这里可以不用再从requests模块import了:

import requests
from requests import ReadTimeout
 
 
def get_page(url):
 try:
  response = requests.get(url, timeout=1)
  if response.status_code == 200:
   return response.text
  else:
   print('Get Page Failed', response.status_code)
   return None
 except (ConnectionError, ReadTimeout):
  print('Crawling Failed', url)
  return None
 
 
def main():
 url = 'https://www.baidu.com'
 print(get_page(url))
 
 
if __name__ == '__main__':
 main()

1.3 用户自定义异常

此外,你也可以通过创建一个新的异常类拥有自己的异常,异常应该是通过直接或间接的方式继承自Exception类。下面创建了一个MyError类,基类为Exception,用于在异常触发时输出更多的信息。

  在try语句块中,抛出用户自定义的异常后执行except部分,变量 e 是用于创建MyError类的实例。

class MyError(Exception):
	def __init__(self, msg):
		self.msg = msg
	
	def __str__(self):
		return self.msg
 
 
try:
	raise MyError('类型错误')
except MyError as e:
	print('My exception occurred', e.msg)

2. 异常捕获

当发生异常时,我们就需要对异常进行捕获,然后进行相应的处理。python的异常捕获常用try...except...结构,把可能发生错误的语句放在try模块里,用except来处理异常,每一个try,都必须至少对应一个except。此外,与python异常相关的关键字主要有:

关键字 关键字说明
try/except 捕获异常并处理
pass 忽略异常
as 定义异常实例(except MyError as e)
else 如果try中的语句没有引发异常,则执行else中的语句
finally 无论是否出现异常,都执行的代码
raise     抛出/引发异常

异常捕获有很多方式,下面分别进行讨论。

2.1 捕获所有异常

包括键盘中断和程序退出请求(用sys.exit()就无法退出程序了,因为异常被捕获了),因此慎用。

try:
     <语句>
 
except:
 
      print('异常说明')

2.2 捕获指定异常

try:
     <语句>
 
except <异常名>:
 
      print('异常说明')

万能异常:

try:
     <语句>
 
except Exception:
 
      print('异常说明')

一个例子:

try:
    f = open("file-not-exists", "r")
 
except IOError as e:
 
    print("open exception: %s: %s" %(e.errno, e.strerror))

2.3 捕获多个异常

捕获多个异常有两种方式,第一种是一个except同时处理多个异常,不区分优先级:

try:
     <语句>
 
except (<异常名1>, <异常名2>, ...):
 
      print('异常说明')

第二种是区分优先级的:

try:
     <语句>
 
except <异常名1>:
 
      print('异常说明1')
 
except <异常名2>:
 
      print('异常说明2')
 
except <异常名3>:
 
      print('异常说明3')

该种异常处理语法的规则是:

  • 执行try下的语句,如果引发异常,则执行过程会跳到第一个except语句。
  • 如果第一个except中定义的异常与引发的异常匹配,则执行该except中的语句。
  • 如果引发的异常不匹配第一个except,则会搜索第二个except,允许编写的except数量没有限制。
  • 如果所有的except都不匹配,则异常会传递到下一个调用本代码的最高层try代码中。

2.4 异常中的else

如果判断完没有某些异常之后还想做其他事,就可以使用下面这样的else语句。

try:
     <语句>
 
except <异常名1>:
 
      print('异常说明1')
 
except <异常名2>:
 
      print('异常说明2')
 
else:
 
      <语句>  # try语句中没有异常则执行此段代码

2.5 异常中的finally

try...finally...语句无论是否发生异常都将会执行最后的代码。

try:
     <语句>
 
finally:
 
      <语句>

看一个示例:

str1 = 'hello world'
try:
    int(str1)
except IndexError as e:
    print(e)
except KeyError as e:
    print(e)
except ValueError as e:
    print(e)
else:
    print('try内没有异常')
finally:
    print('无论异常与否,都会执行我')

2.6 raise主动触发异常

可以使用raise语句自己触发异常,raise语法格式如下:

raise [Exception [, args [, traceback]]]

语句中Exception是异常的类型(例如ValueError),参数是一个异常参数值。该参数是可选的,如果不提供,异常的参数是"None"。最后一个参数是跟踪异常对象,也是可选的(在实践中很少使用)。

看一个例子:

def not_zero(num):
    try:
        if num == 0:
            raise ValueError('参数错误')
        return num
    except Exception as e:
        print(e)
 
 
not_zero(0)

2.7 采用traceback模块查看异常

发生异常时,Python能“记住”引发的异常以及程序的当前状态。Python还维护着traceback(跟踪)对象,其中含有异常发生时与函数调用堆栈有关的信息。记住,异常可能在一系列嵌套较深的函数调用中引发。程序调用每个函数时,Python会在“函数调用堆栈”的起始处插入函数名。一旦异常被引发,Python会搜索一个相应的异常处理程序。如果当前函数中没有异常处理程序,当前函数会终止执行,Python会搜索当前函数的调用函数,并以此类推,直到发现匹配的异常处理程序,或者Python抵达主程序为止。这一查找合适的异常处理程序的过程就称为“堆栈辗转开解”(StackUnwinding)。解释器一方面维护着与放置堆栈中的函数有关的信息,另一方面也维护着与已从堆栈中“辗转开解”的函数有关的信息。

格式如下:

try:
    block
 
except:
 
    traceback.print_exc()

举个栗子:

try:
    1/0
except Exception as e:
    print(e)

如果我们这样写的话,程序只会报“division by zero”错误,但是我们并不知道是在哪个文件哪个函数哪一行出的错。

下面使用traceback模块,官方参考文档:https://docs.python.org/2/library/traceback.html

import traceback
 
try:
    1/0
except Exception as e:
    traceback.print_exc()

这样就会帮我们追溯到出错点:

Traceback (most recent call last):
  File "E:/PycharmProjects/ProxyPool-master/proxypool/test.py", line 4, in <module>
    1/0
ZeroDivisionError: division by zero

另外,traceback.print_exc()跟traceback.format_exc()有什么区别呢?

区别就是,format_exc()返回字符串,print_exc()则直接给打印出来。即traceback.print_exc()与print(traceback.format_exc())效果是一样的。print_exc()还可以接受file参数直接写入到一个文件。比如可以像下面这样把相关信息写入到tb.txt文件去。

traceback.print_exc(file=open('tb.txt','w+'))

参考博文:

except as e中的‘e'的作用总结

python使用traceback获取详细的异常信息

总结

到此这篇关于Python异常类型以及处理方法的文章就介绍到这了,更多相关Python异常处理内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Django在Win7下的安装及创建项目hello word简明教程
Jul 14 Python
python使用cStringIO实现临时内存文件访问的方法
Mar 26 Python
Python的爬虫程序编写框架Scrapy入门学习教程
Jul 02 Python
Python数据分析之获取双色球历史信息的方法示例
Feb 03 Python
深入浅析python 协程与go协程的区别
May 09 Python
python读取Excel表格文件的方法
Sep 02 Python
NumPy排序的实现
Jan 21 Python
将 Ubuntu 16 和 18 上的 python 升级到最新 python3.8 的方法教程
Mar 11 Python
python 画图 图例自由定义方式
Apr 17 Python
Python字符串查找基本操作代码案例
Oct 27 Python
在python3.9下如何安装scrapy的方法
Feb 03 Python
python实现Nao机器人的单目测距
Sep 04 Python
Python OpenCV 彩色与灰度图像的转换实现
Python深度学习之实现卷积神经网络
python opencv通过4坐标剪裁图片
Jun 05 #Python
Python还能这么玩之只用30行代码从excel提取个人值班表
Jun 05 #Python
拒绝盗图!教你怎么用python给图片加水印
python四个坐标点对图片区域最小外接矩形进行裁剪
Python OpenCV 图像平移的实现示例
You might like
php中文字符串截取方法实例总结
2014/09/30 PHP
简单的pgsql pdo php操作类实现代码
2016/08/25 PHP
浅谈PHP中的Trait使用方法
2019/03/22 PHP
php文件上传原理与实现方法详解
2019/12/20 PHP
BAT及各大互联网公司2014前端笔试面试题--JavaScript篇
2014/10/29 Javascript
nodejs初步体验篇
2015/11/23 NodeJs
javascript制作照片墙及制作过程中出现的问题
2016/04/04 Javascript
JavaScript——DOM操作——Window.document对象详解
2016/07/14 Javascript
JavaScript提高网站性能优化的建议(二)
2016/07/24 Javascript
js表单元素checked、radio被选中的几种方法(详解)
2016/08/22 Javascript
AngularJs ng-route路由详解及实例代码
2016/09/14 Javascript
jquery网页日历显示控件calendar3.1使用详解
2016/11/24 Javascript
jQuery.parseHTML() 函数详解
2017/01/09 Javascript
vue如何实现observer和watcher源码解析
2017/03/09 Javascript
详解基于 Nuxt 的 Vue.js 服务端渲染实践
2017/10/24 Javascript
用JS实现根据当前时间随机生成流水号或者订单号
2018/05/31 Javascript
在博客园博文中添加自定义右键菜单的方法详解
2020/02/05 Javascript
js实现小时钟效果
2020/03/25 Javascript
常见的python正则用法实例讲解
2016/06/21 Python
python下解压缩zip文件并删除文件的实例
2018/04/24 Python
python 定时任务去检测服务器端口是否通的实例
2019/01/26 Python
python异常触发及自定义异常类解析
2019/08/06 Python
30秒学会30个超实用Python代码片段【收藏版】
2019/10/15 Python
关于pytorch中全连接神经网络搭建两种模式详解
2020/01/14 Python
python用Configobj模块读取配置文件
2020/09/26 Python
Django如何使用asyncio协程和ThreadPoolExecutor多线程
2020/10/12 Python
印度尼西亚最完整和最大的在线药房网站:Farmaku.com
2019/11/23 全球购物
外科实习自我鉴定
2013/10/06 职场文书
心碎乌托邦的创业计划书范文
2013/12/26 职场文书
初中科学教学反思
2014/01/21 职场文书
办公室副主任职责范本
2014/03/08 职场文书
会计人员岗位职责
2014/03/19 职场文书
镇政府副镇长群众路线专题民主生活会对照检查材料
2014/09/19 职场文书
分居协议书范本
2014/11/03 职场文书
法人代表证明书范本
2015/06/18 职场文书
表彰大会新闻稿
2015/07/17 职场文书