在Python中使用“assert”有什么用?

时间:2011-02-28 13:11:46

标签: python assert assertions

我一直在阅读一些源代码,在一些地方我已经看到了assert的用法。

这究竟是什么意思?它的用途是什么?

22 个答案:

答案 0 :(得分:887)

assert语句几乎存在于每种编程语言中。它有助于在程序的早期发现问题,原因很明显,而不是后来作为其他一些操作的副作用。

当你这样做......

assert condition

...你告诉程序测试那个条件,并在条件为假时立即触发错误。

在Python中,它大致相当于:

if not condition:
    raise AssertionError()

在Python shell中尝试:

>>> assert True # nothing happens
>>> assert False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

断言可以包含可选消息,您可以在运行解释器时禁用它们。

如果断言失败,则打印消息:

assert False, "Oh no! This assertion failed!"

使用括号像函数一样调用assert。这是一份声明。如果您执行assert(condition, message),那么您将使用assert元组作为第一个参数运行(condition, message)

至于禁用它们,在优化模式下运行python__debug__False,断言语句将被忽略。只需传递-O标志:

python -O script.py

有关相关文档,请参阅here

答案 1 :(得分:361)

注意括号。正如上面已经指出的in Python 3, assert is still a statement,所以与print(..)类推,可以将其推断为assert(..)raise(..),但你不应该。{/ p>

这很重要,因为:

assert(2 + 2 == 5, "Houston we've got a problem")

不同,

不起作用

assert 2 + 2 == 5, "Houston we've got a problem"

第一个不起作用的原因是bool( (False, "Houston we've got a problem") )评估为True

assert(False)语句中,这些只是False周围的冗余括号,用于评估其内容。但是使用assert(False,)括号现在是一个元组,并且非空元组在布尔上下文中求值为True

答案 2 :(得分:118)

正如其他答案所指出的,assert类似于在给定条件不为真的情况下抛出异常。一个重要的区别是,如果使用优化选项编译代码,则会忽略assert语句。 documentation表示assert expression可以更好地描述为等同于

if __debug__:
   if not expression: raise AssertionError

如果您想彻底测试代码,然后在您对所有断言案例都没有失败感到高兴时发布优化版本,那么这将非常有用 - 当优化开启时,__debug__变量变为False且条件将停止评估。如果你依赖断言并且没有意识到它们已经消失,这个功能也可能会让你失望。

答案 3 :(得分:48)

其他人已经为您提供了文档链接。

您可以在交互式shell中尝试以下操作:

>>> assert 5 > 2
>>> assert 2 > 5
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.AssertionError:

第一个语句什么都不做,而第二个语句引发异常。这是第一个提示:断言对于检查在代码的给定位置(通常是开始(前置条件)和函数结束(后置条件))应该为真的条件很有用。

断言实际上与合同编程密切相关,这是一种非常有用的工程实践:

http://en.wikipedia.org/wiki/Design_by_contract

答案 4 :(得分:37)

Python中断言的目的是告知开发人员程序中不可恢复的错误。

断言并非旨在表示预期的错误情况,例如“找不到文件”,用户可以采取纠正措施(或者只是再试一次)。

另一种看待它的方法是说断言在代码中是内部自我检查。他们通过在代码中声明一些不可能的条件来工作。如果这些条件不成立,则意味着程序中存在错误。

如果您的程序没有错误,则永远不会出现这些情况。但是,如果其中一个发生,程序将崩溃并出现断言错误,告诉您确切触发了哪个“不可能”的情况。这样可以更轻松地跟踪和修复程序中的错误。

以下是我撰写的a tutorial on Python’s assertions摘要:

  

Python的assert语句是一种调试辅助工具,而不是处理运行时错误的机制。使用断言的目的是让开发人员更快地找到错误的可能根本原因。除非您的程序中存在错误,否则不应该引发断言错误。

答案 5 :(得分:17)

assert语句有两种形式。

简单形式assert <expression>等同于

if __​debug__:
    if not <expression>: raise AssertionError

扩展表单assert <expression1>, <expression2>等同于

if __​debug__:
    if not <expression1>: raise AssertionError, <expression2>

答案 6 :(得分:14)

断言是一种系统的方法,用于检查程序的内部状态是否与程序员预期的一样,目的是捕获错误。请参阅下面的示例。

>>> number = input('Enter a positive number:')
Enter a positive number:-1
>>> assert (number > 0), 'Only positive numbers are allowed!'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: Only positive numbers are allowed!
>>> 

答案 7 :(得分:12)

来自docs:

Assert statements are a convenient way to insert debugging assertions into a program

在这里,您可以阅读更多内容:http://docs.python.org/release/2.5.2/ref/assert.html

答案 8 :(得分:7)

这是一个简单的例子,将其保存在文件中(假设为b.py)

def chkassert(num):
    assert type(num) == int


chkassert('a')

以及$python b.py

时的结果
Traceback (most recent call last):
  File "b.py", line 5, in <module>
    chkassert('a')
  File "b.py", line 2, in chkassert
    assert type(num) == int
AssertionError

答案 9 :(得分:6)

如果assert之后的语句为true,则程序继续,但如果assert之后的语句为false,则程序会给出错误。就这么简单。

e.g:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError

答案 10 :(得分:4)

在Pycharm中,如果您将assertisinstance一起使用来声明对象的类型,它将允许您在编码时访问父对象的方法和属性,它将自动完成自动。

例如,假设self.object1.object2MyClass对象。

import MyClasss

def code_it(self):
    testObject = self.object1.object2 # at this point, program doesn't know that testObject  is a MyClass object yet
    assert isinstance(testObject , MyClasss) # now the program knows testObject is a MyClass object
    testObject.do_it() # from this point on, PyCharm will be able to auto-complete when you are working on testObject

答案 11 :(得分:3)

C2 Wiki所概述:

  

断言是程序中特定点的布尔表达式,除非程序中存在错误,否则该表达式为真。

您可以使用assert语句来记录您在特定程序点上对代码的理解。例如,您可以记录关于输入(前提条件),程序状态(不变式)或输出(后置条件)的假设或保证。

如果断言失败,这是对您(或您的后继者)的警告,表示您在编写程序时对程序的理解是错误的,并且可能包含错误。

有关更多信息,John Regehr在Use of Assertions上有一篇很棒的博客文章,该文章也适用于Python assert语句。

答案 12 :(得分:2)

如果您想知道python中保留函数的确切内容,请输入help(enter_keyword)

确保您输入的保留关键字是否以字符串形式输入。

答案 13 :(得分:1)

Python 断言基本上是一个调试辅助工具,用于测试代码内部自检的条件。 当代码进入不可能的边缘情况时,Assert使调试变得非常容易。断言检查那些不可能的案例。

我们假设有折扣后计算物品价格的功能:

def calculate_discount(price, discount):
    discounted_price = price - [discount*price]
    assert 0 <= discounted_price <= price
    return discounted_price

这里,discounted_price永远不会小于0且大于实际价格。因此,如果上述条件被违反,断言会引发断言错误,这有助于开发人员识别出不可能发生的事情。

希望有所帮助:)

答案 14 :(得分:1)

我的简短解释是:

  • assert如果表达式为假,则引发AssertionError,否则继续执行代码,如果有逗号,则为AssertionError: whatever after comma,并且代码如下:{{ 1}}

有关此的相关教程:

  

https://www.tutorialspoint.com/python/assertions_in_python.htm

答案 15 :(得分:1)

如在其他答案中所写,assert语句用于检查状态。 该程序在给定点。

我不会重复有关关联的说法 消息,括号或-O选项和__debug__常量。还要先检查the doc 手信息。我将重点关注您的问题:assert的用途是什么? 更确切地说,何时(以及何时不应该)使用assert

assert语句对于调试程序很有用,但不鼓励检查用户 输入。我使用以下经验法则:保留断言以检测 this 不应该发生的情况。一个用户 输入可能不正确,例如密码太短,但这不是 this 不应该发生的情况。如果圆的直径不等于圆的两倍 半径,您处于这不应该发生的情况。

在我看来,最有趣的使用assert的灵感来自 programming by contract为 由B. Meyer在[面向对象的软件构造]( https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction%2C_2nd_Edition ),并以[Eiffel编程语言]( https://en.wikipedia.org/wiki/Eiffel_(programming_language))。你不能完全 使用assert语句按合同模拟编程,但这是 保持意图很有趣。

这是一个例子。假设您必须编写一个head函数(例如 [Haskell中的[head函数]( http://www.zvon.org/other/haskell/Outputprelude/head_f.html)。的 给出的规范是:“如果列表不为空,则返回 列表的第一项”。请查看以下实现:

>>> def head1(xs): return xs[0]

>>> def head2(xs):
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

(是的,可以写成return xs[0] if xs else None,但这不是重点)

如果列表不为空,则两个函数的结果相同,并且此结果 是正确的:

>>> head1([1, 2, 3]) == head2([1, 2, 3]) == 1
True

因此,这两种实现都是(我希望)正确的。当您尝试 取一个空列表的标题:

>>> head1([])
Traceback (most recent call last):
...
IndexError: list index out of range

但是:

>>> head2([]) is None
True

同样,这两种实现都是正确的,因为没有人可以传递空值 列出这些功能(我们不符合规范 )。那是 错误的通话,但是如果您进行这样的通话,可能会发生任何事情。 一个函数引发异常,另一个函数返回一个特殊值。 最重要的是:我们不能依靠这种行为。如果xs为空, 这将起作用:

print(head2(xs))

但这会导致程序崩溃:

print(head1(xs))

为了避免一些意外,我想知道什么时候我传递了一些意外消息 函数的参数。换句话说:我想知道何时可以观察到 行为是不可靠的,因为它取决于实现而不是规范。 当然,我可以阅读规范,但是程序员并不总是仔细阅读 文档。

想象一下,如果我有办法将规范插入代码中以获取 以下效果:当我违反规范时,例如通过传递一个空 列出head,我得到警告。这对写正确的书有很大帮助 (即符合规范)程序。这就是assert 进入现场:

>>> def head1(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     return xs[0]

>>> def head2(xs):
...     assert len(xs) > 0, "The list must not be empty"
...     if len(xs) > 0:
...         return xs[0]
...     else:
...         return None

现在,我们有:

>>> head1([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

并且:

>>> head2([])
Traceback (most recent call last):
...
AssertionError: The list must not be empty

请注意,head1会抛出AssertionError,而不是IndexError。那是 重要,因为AssertionError不是任何运行时错误:它表示 违反规范。我想要警告,但出现错误。 幸运的是,我可以禁用检查(使用-O选项), 但风险自负。我会做到的,崩溃真的很昂贵,并且希望 最好。想象一下,我的程序是嵌入在飞船中的, 黑洞。我将禁用断言,并希望程序足够强大 尽可能不崩溃。

此示例仅与前提条件有关,因为您可以使用assert进行检查 后置条件(返回值和/或状态)和不变量(a的状态 类)。请注意,使用assert检查后置条件和不变量可以是 麻烦的:

  • 对于后置条件,您需要将返回值分配给变量,并且 如果正在处理方法,也许可以存储对象的初始状态; <​​/ li>
  • 对于不变式,您必须在方法调用之前和之后检查状态。

您不会拥有像埃菲尔铁塔那样复杂的东西,但是您可以 提高程序的整体质量。


总而言之,assert语句是检测 this的便捷方法 不应该发生的情况。违反规范(例如通过 head的空白列表是头等舱这不应该发生的情况。 因此,尽管assert语句可用于检测任何意外情况, 这是确保符合规范的特权方式。 将assert语句插入代码后,代表 规范,我们希望您已经提高了程序的质量,因为 错误的参数,错误的返回值,错误的类状态..., 将被报告。

答案 16 :(得分:0)

assert语句几乎存在于每种编程语言中。它有助于在程序中尽早发现问题,找出原因,而不是在其他操作后再发现问题。他们总是希望遇到True条件。

当您执行以下操作时:

assert condition

您要告诉程序测试该条件并在错误的情况下立即触发错误。

在Python中,assert expression等效于:

if __debug__:
    if not <expression>: raise AssertionError

您可以使用扩展表达式传递可选消息

if __debug__:
    if not (expression_1): raise AssertionError(expression_2)

在Python解释器中尝试一下:

>>> assert True # Nothing happens because the condition returns a True value.
>>> assert False # A traceback is triggered because this evaluation did not yield an expected value.
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

在使用它们之前,有一些注意事项,主要是针对那些认为在assertif语句之间切换的人。使用assert的目的是在程序验证条件并返回应立即停止程序的值的情况下,而不是采取其他替代方法来绕过错误:

1。括号

您可能已经注意到,assert语句使用两个条件。因此,请勿不要使用括号将其括起来作为明显的建议。如果您这样做,例如:

assert (condition, message)

示例:

>>> assert (1==2, 1==1)
<stdin>:1: SyntaxWarning: assertion is always true, perhaps remove parentheses?

您将运行assert,其中(condition, message)代表一个元组作为第一个参数,这是由于Python中的非空元组总是 True < / strong>。但是,您可以单独进行操作而不会出现问题:

assert (condition), "message"

示例:

>>> assert (1==2), ("This condition returns a %s value.") % "False"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError: This condition returns a False value.

2。调试目的

如果您想知道何时使用assert语句。举一个在现实生活中使用的例子:

*当您的程序倾向于控制用户输入的每个参数或其他任何参数时:

def loremipsum(**kwargs):
    kwargs.pop('bar') # return 0 if "bar" isn't in parameter
    kwargs.setdefault('foo', type(self)) # returns `type(self)` value by default
    assert (len(kwargs) == 0), "unrecognized parameter passed in %s" % ', '.join(kwargs.keys())

*另一种情况是数学运算,当某个方程式的系数或常数为0或非正数时:

def discount(item, percent):
    price = int(item['price'] * (1.0 - percent))
    print(price)
    assert (0 <= price <= item['price']),\
            "Discounted prices cannot be lower than 0 "\
            "and they cannot be higher than the original price."

    return price

*甚至是布尔实现的简单示例:

def true(a, b):
    assert (a == b), "False"
    return 1

def false(a, b):
    assert (a != b), "True"
    return 0

3。数据处理或数据验证

最重要的是不要依赖assert语句来执行数据处理或数据验证,因为可以在Python初始化时使用-O-OO标志关闭此语句–分别表示值1、2和0(默认值)–或PYTHONOPTIMIZE环境变量。

值1:

*断言已禁用;

*个字节码文件是使用.pyo扩展名而不是.pyc生成的。

* sys.flags.optimize设置为1(True);

*并且__debug__设置为False;

值2:禁用了另一项

*文档字符串被禁用;

因此,使用assert语句来验证某种预期数据非常危险,这甚至暗示了某些安全问题。然后,如果您需要验证某些权限,我建议您raise AuthError。作为前提条件,assert通常由程序员在没有用户直接交互的库或模块上使用。

答案 17 :(得分:0)

断言是在我们的程序中自信地陈述事实的陈述。

语法:assert <condition>assert <condition>,<error message>

它具有条件/表达式,该条件/表达式应该始终为真。如果条件为假,则assert语句将暂停程序并抛出一条错误消息,内容为AssertionError。因此,您的断言表达式将是程序中不需要的东西。

例如

  1. assert <condition>-使用断言而不使用<error message>

    var = int(input("Enter value 1-9 inclusive:"))                                 
    assert var!=0 
    print(var)
    

    输出:

    如果输入为0:

    AssertionError
    

    如果输入为1:

    1
    
  2. assert <condition>,<error message>-将断言与<error message>

    一起使用
    var = int(input("Enter value 1-9 inclusive:"))                                 
    assert var!=0,"Input cannot be zero"
    print(var)
    

    输出:

    如果输入为0:

    AssertionError: Input cannot be zero
    

    如果输入为1:

    1
    

关键点:

  1. 它用作调试工具。
  2. 它需要一个表达式和一条可选消息。
  3. 它几乎存在于每种编程语言中

答案 18 :(得分:-2)

def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

可用于确保在函数调用中传递参数。

答案 19 :(得分:-2)

格式:   断言表达式[,参数] 当assert遇到语句时,Python会计算表达式。如果该语句不为true,则会引发异常(assertionError)。 如果断言失败,Python使用ArgumentExpression作为AssertionError的参数。可以使用try-except语句像任何其他异常一样捕获和处理AssertionError异常,但如果不处理,它们将终止程序并产生回溯。 例如:

def KelvinToFahrenheit(Temperature):    
    assert (Temperature >= 0),"Colder than absolute zero!"    
    return ((Temperature-273)*1.8)+32    
print KelvinToFahrenheit(273)    
print int(KelvinToFahrenheit(505.78))    
print KelvinToFahrenheit(-5)    

执行上述代码时,会产生以下结果:

32.0
451
Traceback (most recent call last):    
  File "test.py", line 9, in <module>    
    print KelvinToFahrenheit(-5)    
  File "test.py", line 4, in KelvinToFahrenheit    
    assert (Temperature >= 0),"Colder than absolute zero!"    
AssertionError: Colder than absolute zero!    

答案 20 :(得分:-4)

>>>this_is_very_complex_function_result = 9
>>>c = this_is_very_complex_function_result
>>>test_us = (c < 4)

>>> #first we try without assert
>>>if test_us == True:
    print("YES! I am right!")
else:
    print("I am Wrong, but the program still RUNS!")

I am Wrong, but the program still RUNS!


>>> #now we try with assert
>>> assert test_us
Traceback (most recent call last):
  File "<pyshell#52>", line 1, in <module>
    assert test_us
AssertionError
>>> 

答案 21 :(得分:-4)

基本上,assert关键字含义是如果条件不为真,那么它通过断言错误,否则它继续例如在python中。

码-1

a=5

b=6

assert a==b

输出:

assert a==b

AssertionError

<强>码-2

a=5

b=5

assert a==b

输出:

Process finished with exit code 0