- 在程序运行过程中,总会遇到各种各样的
问题
。- 有的是程序编写有问题造成的,比如,本来应该输出整数,结果输出了字符串,这种问题称为
错误
或bug
,bug
往往是程序员能力不足造成的,bug
是必须修复的。- 还有一类问题是完全可以预测,但无法避免的错误,比如,写入文件时磁盘满了,从网络抓取数据时网络突然中断,我们把这类问题称为
异常
,在程序中通常也是必须处理的,否则程序会终止运行。- 在Python中提供了
try...except...finally...
异常处理机制
语法格式
try:
会引发异常的代码
except 异常类名1 [ as 异常变量名]:
处理异常1的代码
except 异常类名2 [ as 异常变量名]:
处理异常2的代码
...
else:
没有异常时执行的代码
finally:
无论是否有异常,都会执行的代码
- 将某些可能出错的代码放在
try
语句块中执行- 如果执行出错,直接跳转至错误处理代码,即
except
语句块- 执行完
except
后,如果有finally
语句块,则执行finally
语句块- 如果没有异常发生,
except
语句块不会执行,但finally
语句块一定会执行
try:
print('try...')
r = 10 / 0
print('result:', r)
except ZeroDivisionError as e:
print('except:', e)
finally:
print('finally...')
print('END')
try...
except: division by zero
finally...
END
如果发生了不同类型的错误,应该由不同的
except
语句块处理
try:
print('try...')
r = 10 / int('a')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
finally:
print('finally...')
print('END')
int()
函数会抛出ValueError
,除数为0会抛出ZeroDivisionError
。- 在
except
语句块后面加一个else
语句块,当没有错误发生时自动执行
try:
print('try...')
r = 10 / int('2')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
else:
print('no error!')
finally:
print('finally...')
print('END')
Python异常也是一种类,称为
异常类
,所有异常类
都继承自BaseException
类,所以,捕获异常时要先子类、后父类,否则子类异常将无法捕获
try:
foo()
except ValueError as e:
print('ValueError')
except UnicodeError as e:
print('UnicodeError')
第二个
except
永远也捕获不到UnicodeError
,因为UnicodeError
是ValueError
的子类,如果有,也被第一个except
给捕获了
异常的传递
- 当函数或方法执行出现异常时,会将异常传递给调用者,如果传递到主程序,仍然没有异常处理,程序才会被终止
- 因此,只要在合适的层次去捕获错误就可以
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
print('Error:', e)
finally:
print('finally...')
函数
main()
调用foo()
,foo()
调用bar()
,当bar()
出现异常时,只要在main()
中捕获到就可以进行处理
自定义异常类
- 创建一个类,继承自
Exception
类,可以直接或间接继承- 重写
__init__
和__str__
方法
class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return self.value
try:
raise MyError(2*2)
except MyError as e:
print('My exception occurred, value:', e.value)
My exception occurred, value: 4
抛出异常
- 在开发中,除了代码执行出错 Python 解释器会抛出异常之外还可以根据应用程序特有的业务需求主动抛出异常
- 语法格式:
raise [ 异常对象 ]
- 实例演示:密码验证
- 定义
input_password
函数,提示用户输入密码- 如果用户输入长度 < 8,
抛出异常
- 如果用户输入长度 >=8,返回输入的密码
- 处理步骤
- 创建一个
Exception
对象- 使用
raise
关键字抛出异常对象
def input_password():
pwd = input("请输入密码:")
if len(pwd) >= 8:
return pwd
ex = Exception("密码长度不够")
raise ex
try:
user_pwd = input_password()
print(user_pwd)
except Exception as result:
print("发现错误:%s" % result)
请输入密码:1234567
发现错误:密码长度不够
raise
语句如果不带参数,就会把当前异常原样抛出
- 也可以把一种异常类型转化成另一种类型
try:
10 / 0
except ZeroDivisionError:
raise ValueError('input error!')
记录异常信息
- Python内置的
logging
模块可以记录错误信息,打印完错误信息后会继续执行,并正常退出- 通过配置,
logging
还可以把错误记录到日志文件里,方便排查
- 示例1:分级输出log信息
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d]'
' %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
Tue, 15 Jan 2019 19:49:33 py19.py[line:8] DEBUG debug message
Tue, 15 Jan 2019 19:49:33 py19.py[line:9] INFO info message
Tue, 15 Jan 2019 19:49:33 py19.py[line:10] WARNING warning message
Tue, 15 Jan 2019 19:49:33 py19.py[line:11] ERROR error message
Tue, 15 Jan 2019 19:49:33 py19.py[line:12] CRITICAL critical message
- 示例2:输出异常信息
import logging
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
logging.exception(e)
main()
print('END')
ERROR:root:division by zero
Traceback (most recent call last):
File "err_logging.py", line 13, in main
bar('0')
File "err_logging.py", line 9, in bar
return foo(s) * 2
File "err_logging.py", line 6, in foo
return 10 / int(s)
ZeroDivisionError: division by zero
END
- 示例3:将log信息输出到文件
import logging
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(filename)s[line:%(lineno)d]'
' %(levelname)s %(message)s',
datefmt='%a, %d %b %Y %H:%M:%S',
filename='j:/test.log',
filemode='w')
logging.debug('debug message')
logging.info('info message')
logging.warning('warning message')
logging.error('error message')
logging.critical('critical message')
- end -