Python assert
最后修改于 2024 年 1 月 29 日
在本文中,我们将介绍如何在 Python 中使用断言。我们定义了断言,解释了断言和异常的区别,并展示了它们与单元测试的关系。
断言
断言是代码中的内部自我检查;它们适合开发人员尽早发现错误。断言的目的是在程序早期检测到问题,此时原因清晰,并避免它们作为其他操作的副作用而出现。
断言不应用于数据处理或验证,因为它们在生产环境中会被关闭。有些编程语言,如 Go,不使用断言。其他语言有 assert 语句,但使用频率较低(Java)。
断言与异常
断言是必须为真才能使代码正确的布尔表达式。断言失败会导致代码更正。异常是运行时可能发生的非典型情况的指示。异常可能不会导致代码修复。例如,如果互联网连接中断,或者文件权限不足,用户就必须处理这些情况。断言不应用于处理运行时错误。
契约式设计
契约式设计,或称契约式编程,是一种软件开发实践,开发人员为软件组件定义正式、精确且可验证的接口规范。规范分为前置条件、后置条件和不变量。
前置条件是在代码执行之前必须始终为真的谓词。后置条件是在代码执行之后必须始终为真的谓词。不变量是在所有操作后保持不变的属性。
契约式设计方法是在 20 世纪 80 年代开发的,其灵感来源于商业合同。
断言和单元测试
断言和单元测试在某些方面有重叠,但也有一些区别。断言是对程序内部状态的假设,而单元测试则检查模块的外部行为。单元测试使用测试数据,而断言不使用。
Assert 语句用于单元测试。经典的断言是对某事属实的假设,而在单元测试中,开发人员通常会测试 false 条件。
Python assert
assert 语句是向 Python 程序插入调试断言的便捷方法。assert 语句会随着 -O、-OO 选项和 PYTHONOPTIMIZE 变量而被移除。
Python 的 assert 语句由一个布尔条件和一个可选的错误消息组成,用逗号分隔。
Python assert 示例
以下示例展示了 Python assert 语句的用法。
#!/usr/bin/python
def info(age, name):
assert age >= 18 and age <= 65, 'age value must be between values 18 and 65'
print(f'{name} is {age} years old')
age = 84
name = 'Peter'
info(age, name)
在示例中,我们有一个关于 age 值的先决条件。
$ ./precondition.py
Traceback (most recent call last):
File "./precondition.py", line 14, in <module>
info(age, name)
File "./precondition.py", line 6, in info
assert age >= 18 and age <= 65, 'age value must be between values 18 and 65'
AssertionError: age value must be between values 18 and 65
程序失败,因为先决条件无效。
#!/usr/bin/python
def do_discount(price, discount):
discounted_price = price - discount * price
assert 0 < discounted_price < price, 'discounted price must be greater than zero and lower than original price'
return discounted_price
price = 120
discount = 0.2
dis_price = do_discount(price, discount)
print(dis_price)
第二个示例有一个关于折扣价的后置条件。它必须大于零且小于原始价格。
Python 单元测试中的断言
Python 有几个流行的单元测试框架,包括 pytest、unittest 和 nose。虽然 pytest 和 nose 使用 assert 语句,但 unittest 更倾向于使用 assertEqual 和 assertLess 等函数。
Pytest 示例
以下示例展示了 pytest 框架的用法。
def max(values):
_max = values[0]
for val in values:
if val > _max:
_max = val
return _max
def min(values):
_min = values[0]
for val in values:
if val < _min:
_min = val
return _min
我们在一个模块中有两个算法。
#!/usr/bin/python
import algo
def test_min():
values = (2, 3, 1, 4, 6)
val = algo.min(values)
assert val == 1
def test_max():
values = (2, 3, 1, 4, 6)
val = algo.max(values)
assert val == 6
我们将测试数据传递给被测试的 algo 函数。我们使用 assert 语句来检查预期的值。
$ pytest-3 min_max_test.py ============================================================= test session starts ============================================================= platform linux -- Python 3.7.6, pytest-4.6.9, py-1.8.1, pluggy-0.13.0 rootdir: /root/Documents/prog/python/assert collected 2 items min_max_test.py ..
我们运行测试。
Unittest 示例
现在我们用 unittest 测试同一个模块。
#!/usr/bin/python
import unittest
import algo
class SimpleTest(unittest.TestCase):
def test_min(self):
values = (2, 3, 1, 4, 6)
val = algo.min(values)
self.assertEqual(val, 1)
def test_max(self):
values = (2, 3, 1, 4, 6)
val = algo.max(values)
self.assertEqual(val, 6)
if __name__ == '__main__':
unittest.main()
在示例中,我们使用了 assertEqual 断言。
$ ./min_max_test.py .. ---------------------------------------------------------------------- Ran 2 tests in 0.000s OK
我们运行测试。
来源
在本文中,我们讨论了 Python assert 语句,并解释了断言的通用概念。
作者
列出所有 Python 教程。