异常(错误) 的捕获、处理,主要的语法是 try、except、finally,参考代码如下:
try:
1/0
except ZeroDivisionError:
print('ZeroDivisionError')
except Exception as e: # 获得具体的错误作为变量,e
print(type(e), e)
finally:
print('done')
代码中,我们先用 1/0
来主动触发错误,然后用 except
来捕获,except
可以多个连续使用,按照次序先捕获到的处理了,后续的 except 就不运行了。
finally
可以有,也可以没有。它的意思: try 的代码块,成功运行了,finnally 内的会执行;如果 try 的失败了,被 except 捕获了,最后,finnaly 的也会执行。
另外,可以用 pass
这样空代码,来忽略所有的异常。
try:
1/0
except:
pass
有人认为有异常要抛出来,可以发现程序本身的问题;有人认为要尽量处理掉,才能保证程序稳健。
关于如何处理异常的 理念
,倒不重要,公说公有理,婆说婆有理,实践过程中,自己权衡。
异常 虽然等同于 错误,但叫做 异常 会确切一些。错误
,我们应该是要想办法避免的,异常
则未必,它是一种 显著特征。当 try 失败之后,就可以有一个后备的逻辑在某个 except 中对应。
当然,另外一方面,异常 就是 错误,错误 就是 Bug。
所以,一个 Exception 作为 异常 还是 错误,具体情况具体分析,没有完全定论,由你自己视情况而定。
主动触发 异常,是 raise Exception
这个语法。如果异常主动触发,意味着两点: 1. 当前程序直接跳出到对应的异常处理中 (跟循环中的 break 有点异曲同工的感觉);2,针对不同的异常类型,或许需要进入另外的代码逻辑对应。
如果我们从头构建一个产品,有些时候需要自定义一些异常,按需进行触发,以方便不同流程间快速的切换,甚至可以作为另一种层面的 if-else。参考代码如下:
>>> class MyException(Exception):
... pass
...
>>> raise MyException
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
__main__.MyException
一般我们在开发的过程中,利用 PyCharm 进行 Debug 就可以了,即使没有添加过 断点
,异常如果抛出,PyCharm 中也会很容易发现异常发生的位置,然后添加断点,后续再复现查看就可以了。
产品正式上线了,直接 Debug 就不大可能,这个时候,一般会使用 https://sentry.io/,它本身是开源的 https://github.com/getsentry/sentry,可以独立部署到自己的 VPS 上。
下面,我们看一下如何呈现 (print) 遇到的 Exception,参考代码:
import sys
def capture_error():
error_info = sys.exc_info()
if not error_info:
return
e_type, value, tb = error_info[:3]
try: traceback.print_exception(e_type, value, tb)
except: pass
如果想把错误的日志,写入到某个日志文件,参考代码:
import sys
error_filepath = 'error.log'
def capture_error_into_file():
error_info = sys.exc_info()
if not error_info:
return
e_type, value, tb = error_info[:3]
try:
with open(error_filepath, 'a') as f:
traceback.print_exception(e_type, value, tb, file=f)
except:
pass
在上面代码中,open(error_filepath, 'a')
这里用了 a
模式打开一个文件,a
模式的意思是 append
,也就是: 如果文件不存在,创建一个;如果已经存在了,就在末尾添加新内容。
如果我们写了一个客户端的程序,用户使用过程中出现了错误,甚至导致了闪退,这个时候,可以使用上文提到的 sentry 记录错误。另外,也可以直接将错误日志写入到本地的日志文件中。
每一个地方都 try、except
,一来很麻烦,二来代码看起来也会比较难看。有没有一个全局的捕获错误的方式?Python 默认全局提供了 hook 机制。但处理这个 hook 要特别注意了,别在处理错误的时候,又触发了新的错误……
参考代码如下:
import sys
sys.excepthook = capture_error_into_file
# exceptbook 需要赋值一个函数,用于处理系统全局捕获到的异常