# 錯誤處理
[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