1.异常
1.1.异常处理
python内置了一套try...except...else...finally...的错误处理机制。
①当认为某个代码块可能出错,可通过try来运行此段代码,若出错则跳转到except语句块,执行完except之后,若有finally语句块则执行finally语句块,至此,执行完毕。此外,except之后可以加一个else,当没有错误发生时,会自动执行else语句。
②处理异常的方式又多种,如下代码。
③异常是一个class,所有的异常类型均继承自BaseException,except不但捕获该类型的错误,还将其子类“一网打尽”(ValueError --> UnicodeError)
④常见的错误类型和继承关系如下:
BaseException +-- SystemExit +-- KeyboardInterrupt +-- GeneratorExit +-- Exception +-- StopIteration +-- StopAsyncIteration +-- ArithmeticError | +-- FloatingPointError | +-- OverflowError | +-- ZeroDivisionError +-- AssertionError +-- AttributeError +-- BufferError +-- EOFError +-- 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 +-- SyntaxError | +-- IndentationError | +-- TabError +-- SystemError +-- TypeError +-- ValueError | +-- UnicodeError | +-- UnicodeDecodeError | +-- UnicodeEncodeError | +-- UnicodeTranslateError +-- Warning +-- DeprecationWarning +-- PendingDeprecationWarning +-- RuntimeWarning +-- SyntaxWarning +-- UserWarning +-- FutureWarning +-- ImportWarning +-- UnicodeWarning +-- BytesWarning +-- ResourceWarning
⑤异常的捕获还有一个巨大的好处,就是可以跨越多层调用,即:不需要再每个可能出错的地方去捕获错误,只要在合适的层次去捕获错误即可
try:
print("try__")
result = 10/int("a")
# result = 10/0
print("result:%s" % result)
# 方式一
# except ValueError as e:
# print("ValueError:", e)
# except ZeroDivisionError as e:
# print("ZeroDivisionError:", e)
# 方式二
# except (ValueError, ZeroDivisionError) as e:
# print("Error:", e)
# 方式三:不推荐
except Exception as e:
print("Exception:", e)
else:
print("No error!")
finally:
print("finally都会执行")
print("end")
1.2.记录异常
【问题】若不捕获异常,python解释器会打印出错误堆栈,同时程序也会被结束;
既然可以捕获异常,将错误的堆栈打印出来,然后分析错误原因,同时可以让程序继续执行下去。python内置的logging模块可以非常容易的记录错误信息(日志),方便事后排查。
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)
# bar("0")
if "__main__" == __name__:
main()
print("End")
# print(logging.INFO)
# print("2End")
1.3.抛出异常
①异常时一个class,捕获一个异常就是捕获到该class的一个实例。因此,异常可自行定义,并抛出
②特殊形式:捕获异常的目的仅仅是为了记录一下,便于后续追踪。但当前函数不知道如何处理该错误,所以,最恰当的方式是继续往上抛出,让顶层调用者去处理。raise语句不带参数就会把当前错误原样抛出。此外,在raise的过程中还可以把一种错误类型转换成另外一种类型。
def foo(s):
n = int(s)
if 0 == n:
raise ValueError("invalid value===%s" % s)
return 10/n
def bar():
try:
foo("0")
except ValueError as e:
print("ValueError!", e)
raise
if "__main__" == __name__:
bar()
2.调试
2.1.print语句打印错误信息
最简单的调试方式是直接通过print打印相关引用的信息来进行判断,但该种方式在使用过程中存在一个问题:程序写完之后还需要逐行删除或注释。
2.2.assert断言
①通过print来辅助查看的地方均可通过assert断言来替代;若断言失败,则抛出AssertionError异常。
②启用python解释器时,可通过参数-O来关闭assert。(python -O a.py)
def foo(s):
n = int(s)
assert n != 0
return 10/n
if "__main__" == __name__:
foo("0")
# Traceback (most recent call last):
# File "E:/...程序调试.py", line 15, in <module>
# foo("0")
# File "E:/...程序调试.py", line 9, in foo
# assert n!= 0
# AssertionError