调试Python程序时,经常会报出一些异常,异常的原因一方面可能是写程序时由于疏忽或者考虑不全导致的错误,这时就要根据捕获的异常定位出错点,进行分析改正;另一方面,有些异常是不可避免的,但我们可以对异常进行捕获处理,防止程序终止。
一、什么是异常
异常是一个事件,在程序运行的时候发生错误触发的,影响了程序的正常执行。如果我们不在程序运行过程中,捕获异常,那么程序就有可能终止运行。
在python中,由于错误触发的异常如下:
二、python异常类型
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- ImportError | +-- ModuleNotFoundError +-- LookupError | +-- IndexError | +-- KeyError +-- MemoryError +-- NameError | +-- UnboundLocalError +-- OSError | +-- BlockingIOError | +-- ChildProcessError | +-- ConnectionError | | +-- BrokenPipeError | | +-- ConnectionAbortedError | | +-- ConnectionRefusedError | | +-- ConnectionResetError | +-- FileExistsError | +-- FileNotFoundError | +-- InterruptedError | +-- IsADirectoryError | +-- NotADirectoryError | +-- PermissionError | +-- ProcessLookupError | +-- TimeoutError +-- ReferenceError +-- RuntimeError | +-- NotImplementedError | +-- RecursionError +-- SyntaxError | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning
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 # 请求的基本警告
AttributeError: 试图访问一个对象没有的属性,比如foo.x,但是foo没有属性x IOError:输入 / 输出异常,一般是无法打开文件 ImportError: 无法导入模块或包,一般是路径问题或名称错误 IndentationError:代码没有正确对齐,属于语法错误 IndexError:下标索引超出序列边界,比如x只有三个元素,却试图访问x[3] KeyError:试图访问字典里不存在的键 KeyboardInterrupt:Ctrl + C被按下 NameError:使用一个还未被赋予对象的变量 SyntaxError: 语法错误 TypeError: 传入对象类型与要求的不符 UnboundLocalError:试图访问一个还未被设置的局部变量,一般是由于在代码块外部还有另一个同名变量 ValueError: 传入一个调用者不期望的值,即使值的类型是正确的
三、异常处理
1、if判断处理异常
- if判断式的异常处理只能针对某一段代码,对于不同的代码段的相同类型的错误你需要写重复的if来进行处理。
- 在你的程序中频繁的写与程序本身无关,与异常处理有关的if,会使得你的代码可读性极其的差
- if是可以解决异常的,只是存在以上两个问题。
def is_price(s): s = str(s) if s.isdigit(): return True if s.count('.') == 1: left, right = s.split('.') if left.isdigit() and right.isdigit(): return True return False
2、try处理异常
2.1 捕获异常基本语法
try: <需要捕获异常的代码> except <异常名字> as <返回错信息变量名称>: <出现异常后要执行要执行的代码>
try: <需要捕获异常的代码> except <异常名字> as <返回错信息变量名称>: <出现异常后要执行要执行的代码> else: <没有出现异常要执行的代码>
try: <需要捕获异常的代码> except <异常名字> as <返回错信息变量名称>: <出现异常后要执行要执行的代码> else: <没有出现异常要执行的代码> finally: <无论是否出现异常都要执行的代码>
2.2 try...except工作原理
- 当Python解释器遇到try时,Python会记录程序的上下文,如果程序出现异常时,会回到这里,开始执行try的子句,也就是except里的代码。
- 如果try所包含的代码出现错误,会触发第一个匹配到的except,异常处理完成后,程序继续运行。
- 如果try所包含的代码出现错误后,没有匹配到对应的except,则返回上一层try寻找,直到程序的最上层,然后程序结束。
- 如果在try所包含的代码执行时没有发生异常,Python将执行else语句后的语句(如果有else的话),然后控制流通过整个try语句。
- 当然如果try含有finally,无论是否遇到异常,都会运行下面的代码。
2.3 try捕获异常示例:
1 #未捕获异常,程序运行异常报错终止 2 def read_file(filename): 3 with open(filename) as fr: 4 result=fr.read() 5 print(result) 6 7 read_file("a.txt") 8 9 ==============执行结果================== 10 Traceback (most recent call last): 11 File "D:/python/day7/异常处理.py", line 88, in <module> 12 read_file('t.txt') 13 File "D:/python/day7/异常处理.py", line 25, in read_file 14 with open(filename) as fr: 15 FileNotFoundError: [Errno 2] No such file or directory: 't.txt'
try捕获异常的几种方法实例如下:
1 #try...except...
2 def read_file1(filename):
3 try:
4 with open(filename) as fr: #try子句,首先执行这里的代码
5 result=fr.read()
6 print(result)
7 except Exception as e: # Exception捕获所有异常
8 print('发生异常时执行,读取文件发生错误:%s'%e)
9
10 #try...except...else...
11 def read_file2(filename):
12 try:
13 with open(filename) as fr:
14 result=fr.read()
15 except FileNotFoundError as e: #指定异常,捕获具体的异常
16 print('发生异常时执行,读取文件发生错误:%s'%e)
17 except FileExistsError as e:
18 print('发生异常时执行,读取文件发生错误:%s'%e)
19 else: #没有发生异常时,执行else下面的代码
20 print(result)
21 print('未出现异常执行这里的代码')
22
23 #try...except...else...finally...
24 def read_file3(filename):
25 try:
26 with open(filename) as fr:
27 result=fr.read()
28 except FileNotFoundError as e:
29 print('发生异常时执行,读取文件发生错误:%s'%e)
30 except FileExistsError as e:
31 print('发生异常时执行,读取文件发生错误:%s'%e)
32 else:
33 print(result)
34 print('未出现异常执行这里的代码')
35 finally:
36 print('无论如何都得执行这里的代码')
37
38 #自定义一个异常FError类继承Exception这个异常类,就可以使用了
39 class FError(Exception):
40 pass
41
42 #主动抛出自定义的异常
43 def price():
44 price=input('price:')
45 if not price.isdigit():
46 try:
47 raise FError("输入的价格不是数字") # 主动抛出一个keyerror的异常
48 except FError as e:
49 print('这个是我主动抛出的异常%s'%e)