python中通常用 try……except对程序进行异常捕获处理,以下将用浅显易懂的例子,让你对知识融会贯通!
许多场景中,我们都需要利用异常捕获来处理程序中的异常,比如:处理大量数据时/调用模型时/使用循环时,都有可能因为数据的千奇百怪报出异常,而我们希望针对出现的异常有对应的解决方式,以保证程序完整且正确的运行。这时使用try……except 方法就能完美解决。
try……except的使用方法:想要运行的程序放在try中,而如果有任何问题出现,以except中语句的方式处理它
try:
except :
……
例:要将列表中的每一个元素变为整数
>>>li = [1,2,'-','/','',5]
>>>li_new = []
>>>for i in li:
li_new.append(int(i))
>>>li_new
[1, 2]
面对这种异常,我们可以按自己指定的异常处理方式去处理它,比如遇到不可转为整型的元素,直接转为0
>>>li = [1,2,'-','/','',5]
>>>li_new = []
>>>for i in li:
try:
li_new.append(int(i))
except:
li_new.append(0)
>>>li_new
[1, 2, 0, 0, 0, 5]
由以上的例子我们可以看出,当 Python 遇到 try 语句时,它尝试执行其中的语句:
1、如果这些语句执行没有错误,控制随后转到 try … except 后的下一个语句。
2、如果在其中某处发生错误, Python 会查找具有匹配 错误类型的 except 子句。
3、如果找到合适的 except,则执行处理程序代码。
当我们随着知识的增长,你已经开始写函数了~(此处掌声)那么,你写了如下一个函数,尝试用程序解决开方问题:
# 导入模块
>>>import math
>>>def get_sqrt(x):
return math.sqrt(x)
>>>get_sqrt(2)
1.4142135623730951
这个函数可以轻易对任意非负数进行开平方的运算,你充满信心的把程序发给小明,对他说:“你可以用这个函数进行开方计算,保证万无一失!”
然后还没有学过开平方计算的小明进行了如下操作:
>>>get_sqrt(-2)
小明说:“你这个用不了啊?这是什么结果?”
你恍然大悟:“我写的函数前提是用的人得知道只能用非负数呀!这不行,我得再改改。”
既然会发生“数值错误”,那就针对这个错误进行异常捕获。
# 如果不进行异常处理,那么调用函数会直接报错
>>>def get_sqrt(x):
try:
return math.sqrt(x)
except ValueError:
return 'No such result'
>>>get_sqrt(-2)
'No such result'
做了异常捕获后,你更是充满信心,这次绝对不会报错了,于是你把函数发给李华,“常常需要别人帮忙用英语写信”的李华此时也信心满满地将’x’传入了函数:
>>>get_sqrt('x')
此时报出的错误是“类型错误:必须是一个数字而不是字符串”
这还不简单!再来个except 接着做异常处理:
>>>def get_sqrt(x):
try:
return math.sqrt(x)
except ValueError:
return 'No such result'
except TypeError:
return 'Invalid given'
>>>get_sqrt('x')
'Invalid given'
你成功的解决了另一个报错问题,但是这还只是一个简单的函数,如果之后你写了更复杂的程序,有许多你无法测试出的异常并避免,怎么办呢?到底能有多少种异常呢?
所有内置异常都继承了Exception类
── Exception
├── ArithmeticError
│ ├── FloatingPointError
│ ├── OverflowError
│ └── ZeroDivisionError
├── AssertionError
├── AttributeError
├── BufferError
├── EOFError
├── ExceptionGroup [BaseExceptionGroup]
├── 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
├── StopAsyncIteration
├── StopIteration
├── SyntaxError
│ └── IndentationError
│ └── TabError
├── SystemError
├── TypeError
├── ValueError
│ └── UnicodeError
│ ├── UnicodeDecodeError
│ ├── UnicodeEncodeError
│ └── UnicodeTranslateError
└── Warning
├── BytesWarning
├── DeprecationWarning
├── EncodingWarning
├── FutureWarning
├── ImportWarning
├── PendingDeprecationWarning
├── ResourceWarning
├── RuntimeWarning
├── SyntaxWarning
├── UnicodeWarning
└── UserWarning
有这么多的异常类型,如果想要给每一个异常都编写对应的except是不可能的。
# 方法一:设定一个except代码组,用来捕捉指定异常外的所有异常
>>>def get_sqrt(x):
try:
return math.sqrt(x)
except ValueError:
return 'No such result'
except TypeError:
return 'Invalid given'
except:
return 'Other error'
# 方法二:pass——忽略异常
>>>def get_sqrt(x):
try:
return math.sqrt(x)
except:
pass
# pass为忽略异常,并不显示出现了什么问题,并不推荐使用
虽然以上两种方法不会暴露跟踪回溯的消息,但是不再知道代码遇到的特定问题。
了解出现了什么异常很重要,这样方便在处理异常的同时得到与之关联的数据。
# 方法三: except Exception
# 使用 Exception 就可以让一个 except 捕捉所有异常
>>>def get_sqrt(x):
try:
return math.sqrt(x)
except Exception as ex:
return str(ex)
# 不输出对应错误类型,直接输出错误
>>>get_sqrt(-2)
'math domain error'
>>>get_sqrt('x')
'must be real number, not str'
如果你想知道异常更多的信息,还可以使用sys模块。
方法四:sys模块
'''
sys模块中的exc_info()可以提供当前处理的异常的有关信息
'''
# 导入模块
>>>import sys
>>>def get_sqrt(x):
try:
return math.sqrt(x)
except:
ex = sys.exc_info()
return ex
>>>get_sqrt(-2)
(ValueError, ValueError('math domain error'), <traceback at 0x7f96c0057b40>)
>>>get_sqrt('x')
(TypeError,
TypeError('must be real number, not str'),
<traceback at 0x7f96b27cd7d0>)
exc_info()返回一个三元组,第一个值为异常类型;第二个值为详细描述异常的问题;第三个值是回溯跟踪对象。
# 导入模块
>>>import pandas as pd
>>>df = pd.DataFrame({'A': [1, 2, 3, 4]})
>>>dff = df.query('A == 2')
>>>dff['A'] = 3
切片后直接赋值,出现了警告提示。exception类中也有Warning,那么使用处理异常的方法能否解决警告呢?
>>>try:
df = pd.DataFrame({'A': [1, 2, 3, 4]})
dff = df.query('A == 2')
dff['A'] = 3
except Warning as ex:
print(ex)
# 将警告设置为异常
# 导入模块
>>>import warnings
>>>warnings.filterwarnings('error')
>>>try:
df = pd.DataFrame({'A': [1, 2, 3, 4]})
dff = df.query('A == 2')
dff['A'] = 3
except Warning as ex:
print(ex)
# 如果语句没有异常,执行完try后执行else
# 如果有异常,只执行except
>>>i = 0
>>>while i < 3:
try:
a = input('input number:')
print(math.sqrt(int(a)))
except ValueError:
print('No such result')
except TypeError:
print('Invalid given')
except Exception as ex:
print(ex)
else:
print("output number is",math.sqrt(int(a)))
i+=1
# 无论执行try还是except,都会接着执行finally
>>>i = 0
>>>while i <3:
try:
a = input('input number:')
print(math.sqrt(int(a)))
except ValueError:
print('No such result')
except TypeError:
print('Invalid given')
except Exception as ex:
print(ex)
finally:
print("我执行啦")
i+=1
由以上的例子我们可以学到:
1、异常捕获处理的方法:try……except 组合语句,将能正常运行的语句放在try后面,将会出现异常并进行异常处理的语句放在except后面。
2、如果一个except 不能解决所有异常,那么可以使用多个except解决。
3、捕获所有异常的方法:exception类和 sys模块的exc_info()函数。
4、想要捕获警告,可以先将警告设置为异常,再使用异常捕获方法。
5、异常捕获处理的更多结合应用:
1)try……except……else 中 try 和 else一起执行,遇到异常执行except;
2)try……except……finally 中 finally的语句在执行异常捕获之后都会执行
虽然知道了这么多异常捕获的知识点,但是希望大家都能不遇到异常(手动狗头)