作者 | luanhz

程序员每天遇到 bug 就像喝水吃饭一样稀松平常,关键在于怎么高效而不失优雅的面对这些 bug!所以,你还在固执的使用 try……except 吗?

为了提高程序运行的稳健性,几乎所有语言都提供了 try……except……用法, Python 也不例外。虽然 try……except……语法能够确保程序能够跳过异常代码片段,无论如何都继续执行下去,但有时主动的触发报错和异常也是一种行之有效的程序员装X护体方法。

本文主要介绍 Python 中的两个异常相关的关键字:assert 和 raise,前者用于断言发现潜在异常,后者用于触发报错,实际上二者功能有很大相近之处。

Python异常分类

Python内置了数十种Exception/Error类型,例如常见的如下几种:

IndexError,索引错误,例如引用了超出列表长度的索引

KeyError,键值错误,例如引用了字典中不存在的键值

NameError,未声明错误,例如引用了未赋值的对象或变量

SyntaxError,语法错误,广泛存在

IndentationError,缩进错误,这是Python摒弃花括号而用缩进区分代码段的特色产物

TypeError,类型错误,例如执行数字和字符串相加会引发此类错误

这些错误很常见,也比较直观易懂。但有没有考虑过主动触发这些错误呢?

assert:断言

assert 一般用于函数和类的内部,在执行具体逻辑前首先对输入参数和程序执行状态进行一定的检查和预判,仅当执行状态满足时才继续执行后续的逻辑,否则断言条件不满足,引发后续的提示。

assert 关键字基本用法为:

assert "条件判断", "条件不满足时输出的提示信息"

例如,设计一个两数相除的函数,那么应当在执行相除前检查:

两个输入参数是否为数值型

除数是否不为0

这一条件判断可用assert完成,并在条件不满足时优雅的提示报错:

def div(x, y):assert isinstance(x, (float, int)) and isinstance(y, (float, int)), \"param `x` and `y` expected to be 'int' or 'float' type"assert y != 0, "param `y` should not to be exactly `0`"return x/ydiv(1, "2")---------------------------------------------------------------------------AssertionError Traceback (most recent call last)input-206-579e0bede4d8> in----> 1 div(1, "2")input-205-258ec937e818> in div(x, y)1 def div(x, y):2 assert isinstance(x, (float, int)) and isinstance(y, (float, int)), \----> 3 "param `x` and `y` expected to be 'int' or 'float' type"4 assert y != 0, "param `y` should not to be exactly `0`"5 return x/yAssertionError: param `x` and `y` expected to be 'int' or 'float' type

由于输入参数y是字符串类型,断言失败,引发断言错误

相较于 try……except……用法,assert 的最大意义在于能够及时发现程序中未按预期状态执行的错误,这在多人协作 coding 过程中,比 except 更能提供丰富的报错信息。

raise:触发异常

实际上,raise 关键字的哲学与 assert 是有相通之处的,只不过 assert 包含逻辑判断和触发提示信息两部分内容,而 raise 则只用于手动触发异常,且一般触发的是 Python 内置异常类型。某种程度上,raise 的灵活性要比 assert 低,在个人实际使用过程中也几乎很少用到。

raise关键字基本语法为:

raise 异常类名称(描述信息)

例如,仍以实现上述 div 函数功能为例,以 raise 关键字执行同样的断言功能,则可如下实现:

def div(x, y):if not isinstance(x, (float, int)) or not isinstance(y, (float, int)):raise TypeError("param `x` and `y` expected to be 'int' or 'float' type")if y == 0:raise ZeroDivisionError("param `y` should not to be exactly `0`")return x/ydiv(1, 0)---------------------------------------------------------------------------ZeroDivisionError Traceback (most recent call last)input-213-4267cdef819f> in----> 1 div(1, 0)input-212-dce337c4d91a> in div(x, y)3 raise TypeError("param `x` and `y` expected to be 'int' or 'float' type")4 if y == 0:----> 5 raise ZeroDivisionError("param `y` should not to be exactly `0`")6 return x/yZeroDivisionError: param `y` should not to be exactly `0`

由于除数为0,raise关键字触发异常

以上就是 Python 中这两个关键字的简单用法,单论其实质功能而言都称不上是不可或缺,甚至可能会觉得有些鸡肋,但不得不说在某些场景下二者其实都还是有用武之地,或许届时你的代码也可以如大佬一般:优雅高效,同时略显装X!