ZetCode

Python assert

最后修改于 2024 年 1 月 29 日

在本文中,我们将介绍如何在 Python 中使用断言。我们定义了断言,解释了断言和异常的区别,并展示了它们与单元测试的关系。

断言

断言是代码中的内部自我检查;它们适合开发人员尽早发现错误。断言的目的是在程序早期检测到问题,此时原因清晰,并避免它们作为其他操作的副作用而出现。

断言不应用于数据处理或验证,因为它们在生产环境中会被关闭。有些编程语言,如 Go,不使用断言。其他语言有 assert 语句,但使用频率较低(Java)。

注意: Go 的设计者解释说,开发人员应该更多地考虑正确的错误处理和报告。Go 只在单元测试中有断言。

断言与异常

断言是必须为真才能使代码正确的布尔表达式。断言失败会导致代码更正。异常是运行时可能发生的非典型情况的指示。异常可能不会导致代码修复。例如,如果互联网连接中断,或者文件权限不足,用户就必须处理这些情况。断言不应用于处理运行时错误。

契约式设计

契约式设计,或称契约式编程,是一种软件开发实践,开发人员为软件组件定义正式、精确且可验证的接口规范。规范分为前置条件、后置条件和不变量。

前置条件是在代码执行之前必须始终为真的谓词。后置条件是在代码执行之后必须始终为真的谓词。不变量是在所有操作后保持不变的属性。

契约式设计方法是在 20 世纪 80 年代开发的,其灵感来源于商业合同。

断言和单元测试

断言和单元测试在某些方面有重叠,但也有一些区别。断言是对程序内部状态的假设,而单元测试则检查模块的外部行为。单元测试使用测试数据,而断言不使用。

Assert 语句用于单元测试。经典的断言是对某事属实的假设,而在单元测试中,开发人员通常会测试 false 条件。

Python assert

assert 语句是向 Python 程序插入调试断言的便捷方法。assert 语句会随着 -O-OO 选项和 PYTHONOPTIMIZE 变量而被移除。

Python 的 assert 语句由一个布尔条件和一个可选的错误消息组成,用逗号分隔。

Python assert 示例

以下示例展示了 Python assert 语句的用法。

precondition.py
#!/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

程序失败,因为先决条件无效。

postcondition.py
#!/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 有几个流行的单元测试框架,包括 pytestunittestnose。虽然 pytestnose 使用 assert 语句,但 unittest 更倾向于使用 assertEqualassertLess 等函数。

Pytest 示例

以下示例展示了 pytest 框架的用法。

algo.py
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

我们在一个模块中有两个算法。

min_max_test.py
#!/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 测试同一个模块。

min_max_test.py
#!/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 assert 语句,并解释了断言的通用概念。

作者

我叫 Jan Bodnar,是一位热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出所有 Python 教程