# 错误处理
[TOC]
## 捕获异常
所有的错误类型都继承自BaseException,所以在使用except时需要注意的是,**它不但捕获该类型的错误,还把其子类也“一网打尽”**
[常见的错误类型和继承关系][1]
```
# 有可能用到的
BaseException
+-- Exception
+-- StopIteration
+-- AttributeError
+-- BufferError
+-- LookupError
| +-- IndexError
| +-- KeyError
+-- MemoryError
+-- NameError
| +-- UnboundLocalError
+-- OSError
| +-- FileExistsError
| +-- FileNotFoundError
| +-- TimeoutError
+-- ReferenceError
+-- RuntimeError
| +-- NotImplementedError
| +-- RecursionError
+-- SyntaxError
| +-- IndentationError
| +-- TabError
+-- SystemError
+-- TypeError
+-- ValueError
```
```python
try:
print('try...')
r = 10 / int('a')
# r = 10 / 2
print('result:', r)
except ValueError as e:
print('ValueError:', e) # ValueError: invalid literal for int() with base 10: 'a'
except ZeroDivisionError as e:
print('ZeroDivisionError:', e) # 不同的错误类型接收不同的错误,父类也会抛出子类的错误
else:
print('no error!') # 没有错误就就执行else
finally:
print('finally...')
print('END')
```
## 记录错误
Python内置的logging模块可以非常容易地记录错误信息,可以设置日志格式,级别,处理器(保存日志到文件,数据库,缓存)
```python
#coding:utf-8
import logging
# 配置了日志输出文件,格式,时间
logging.basicConfig(filename='log1.log',
format='%(asctime)s -%(name)s-%(levelname)s-%(module)s:%(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.DEBUG)
while True:
option = input("input a digit:")
if option.isdigit():
print("hehe",option)
logging.info('option correct')
else:
logging.error("Must input a digit!")
# 日志级别
# logging.debug('有bug')
# logging.info('有新的信息')
# logging.warning('警告信息')
# logging.error('错误信息')
# logging.critical('紧急错误信息')
# logging.log(10,'log')
#coding:utf-8
#coding:utf-8
import logging
# 获取日志实例
logger = logging.getLogger("simple_example")
logger.setLevel(logging.DEBUG)
#输出到屏幕
ch = logging.StreamHandler()
ch.setLevel(logging.WARNING)
#输出到文件
fh = logging.FileHandler("log2.log")
fh.setLevel(logging.INFO)
#设置日志格式
fomatter = logging.Formatter('%(asctime)s -%(name)s-%(levelname)s-%(module)s:%(message)s')
ch.setFormatter(fomatter)
fh.setFormatter(fomatter)
logger.addHandler(ch)
logger.addHandler(fh)
#输出日志
logger.debug("debug message")
logger.info("info message")
logger.warning("warning message")
logger.error("error message")
logger.critical("critical message")
```
用到时具体查看相关文章
[Python中的logging模块][2]
## 抛出错误
### raise
```python
# 可以自定义错误类,但如果可以选择Python已有的内置的错误类型(比如ValueError,TypeError),尽量使用Python内置的错误类型。
class FooError(ValueError):
pass
def foo(s):
n = int(s)
if n==0:
raise FooError('invalid value: %s' % s)
return 10 / n
def bar():
try:
foo('0')
except ValueError as e: # invalid value: 0
print(e)
bar()
```
### reise from
```python
class FooError(ValueError):
def __init__(self, msg, country_code):
self.msg = msg
self.country_code = country_code
def foo(s):
n = int(s)
if n==0:
# 由于内置的错误类可以传入任意的参数
raise FooError('invalid value: %s' % s,22) from ValueError
return 10 / n
def bar():
try:
foo('0')
except FooError as exc:
# 语义化接管了
print(exc.country_code)
bar()
```
## 断言
凡是用print()来辅助查看的地方,都可以用断言(assert)来替代。
```python
def foo(s):
n = int(s)
assert n != 0, 'n is zero!' # 表达式n != 0应该是True,否则,抛出错误AssertionError
return 10 / n
try:
foo(0)
except Exception as e:
# <AssertionError> : n is zero!
print('<%s> : %s' % (e.__class__.__name__,str(e)))
# python -O err.py 启动Python解释器时可以用-O参数来关闭assert
```
## [单元测试] [3]
## [文档测试] [4]
[1]: https://docs.python.org/3/library/exceptions.html#exception-hierarchy
[2]: http://python.jobbole.com/86887/
[3]: https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/00143191629979802b566644aa84656b50cd484ec4a7838000