异常处理
异常类
Python2 在 exceptions
模块内建了很多的异常类型,通过使用 dir
函数来查看 exceptions
中的异常类型
在 python3 中它们是全局的。
捕获异常和获取异常信息
和 C#中的 try/catch 类似,Python 中使用 try/except 关键字来捕捉异常,如下:
try:
print(2 / 0)
except ZeroDivisionError:
print("除数不能为0")
在一个 except 语句只捕捉其后声明的异常类型,如果可能会抛出的是其他类型的异常就需要再增加一个 except 语句了,或者也可以指定一个更通用的异常类型比如:Exception,(也可以不接任何异常和参数直接捕获,但是 pycharm 会给出一个警告的) 如下:
try:
print(2 / "0")
except ZeroDivisionError:
print("除数不能为0")
except Exception:
print("其他类型异常")
每个异常都会有一些异常信息,一般情况下我们应该把这些异常信息记录下来:
try:
print(2 / "0")
except Exception as e: # Exception位置也可以放一个错误类元组
# unsupported operand type(s) for /: 'int' and 'str'
print(e.args)
finally 子句和 try 子句联合使用但是和 except 语句不同,finally 不管 try 子句内部是否有异常发生,都会执行 finally 子句内的代码。所有一般情况下,finally 自己常常用于关闭文件或者在 socket 中。
try:
print(2 / "0")
except (ZeroDivisionError, Exception):
print("发生了一个异常")
else:
print("正常得出了计算结果")
finally:
print("不管是否发生异常都执行")
抛出异常和自定义异常
Python 中的 raise 关键字用于引发一个异常,基本上和 C#和 Java 中的 throw 关键字相同,如下所示:
def ThorwErr():
raise Exception("抛出一个异常")
# Exception: 抛出一个异常
ThorwErr()
raise 关键字后面是抛出是一个通用的异常类型(Exception),一般来说抛出的异常越详细越好。
捕捉到了异常,但是又想重新引发它(传递异常),可以使用不带参数的 raise 语句即可:
class MuffledCalculator:
muffled = False
def calc(self, expr):
try:
return eval(expr)
except ZeroDivisionError:
if self.muffled:
print("Division by zero is illegal")
else:
raise
Python 中也可以自定义自己的特殊类型的异常,只需要要从 Exception 类继承(直接或间接)即可
断言
assert(断言)用于判断一个表达式,在表达式条件为 false 的时候触发异常
assert expression, arguments
相当于
if not expression:
raise AssertionError(arguments)
警告类
和异常类的 exceptions 模块一样,警告类型在 warnings 模块中,
但是事实上 Warning 基类是 Exception 基类的子类。
发出警告
import warnings
warnings.warn("使用了已弃用功能", DeprecationWarning)
忽略警告
调用 filterwarnings()
将规则添加到警告过滤器,simplefilter()
是其简易版。
调用 resetwarnings()
将警告过滤器重置为默认状态。
import warnings
warnings.simplefilter("ignore")
警告上升为异常
import warnings
warnings.simplefilter("error")
上下文管理
以下内容可能超出理解,以后请回看。
with as 语句
在使用内置函数open()
读写文件的时候需要繁琐的方法来捕获异常:
try:
f = open("1.txt")
f.read()
finally:
if f:
f.close()
大可不必如此,open()
返回的文件句柄对象实现了上下文管理,只需要:
with open("1.txt") as f:
f.read()
实现上下文协议
对任意对象实现上下文管理,可以通过实现魔术方法__enter__
和__exit__
class A:
def __init__(self, name):
self.name = name
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
if exc_type:
print(traceback)
__enter__
和__exit__
也可以借由内置模块contextlib
的装饰来实现
from contextlib import contextmanager
@contextmanager
def open_a(name):
yield A(name)
@closing
如果一个对象没有实现上下文,我们就不能把它用于with
语句。这个时候,可以用closing()
来把该对象变为上下文对象
from contextlib import closing
from urllib.request import urlopen
with closing(urlopen("https://www.python.org")) as page:
for line in page:
print(line)
熔断器模式
熔断器模式 Circuit Breaker
熔断器模式可以防止应用程序不断地尝试执行可能会失败的操作,使得应用程序继续执行而不用等待修正错误,或者浪费 CPU 时间去等到长时间的超时产生。熔断器模式也可以使应用程序能够诊断错误是否已经修正,如果已经修正,应用程序会再次尝试调用操作。
熔断器模式就像是那些容易导致错误的操作的一种代理。这种代理能够记录最近调用发生错误的次数,然后决定使用允许操作继续,或者立即返回错误。