Python中“ assert”的用法是什么?


Answers:


1082

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

有关相关文档,请参见此处


92
Nit:assert是一个语句而不是一个函数。而且与print不同,在Python 3中它仍然是一个声明
Bob Stein 2014年

2
@Chaine assert表示“确保* something”为True。因此断言a == 3将确保a等于3;如果a不等于3(即a == 3为False),则它将引发错误
蚂蚁

5
如果我只能使用if not condition: raise AssertError(),为什么要使用assert?除了仅是简短的if not condition陈述形式之外,是否有其他条件可以使assert更好?
alpha_989

6
@ alpha_989 a)它更短并且更易读,b)您可以在运行解释器时禁用assert语句(手册中则不是if)。阅读文档以获取更多信息:)
slezica

9
完全无法获得该答案如何获得如此多的票数,实际上其他人也是如此。问题是“ Python中“ assert”的用途是什么?”,所以它问:什么时候使用,或更确切地说:的使用场景是什么assert,但是在阅读所有答案之后,我什么都没得到!
lnshi

422

注意括号。正如上面指出的那样,在Python 3中,assert它仍然是一条语句,因此与类似print(..),可以将其外推到assert(..)raise(..)但不应该外推。

这很重要,因为:

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布尔值。


18
我来这里是为了寻找有关parens的确切信息以及以下消息。谢谢。
superbeck

6
但是assert (2 + 2 = 5), "Houston we've got a problem"应该可以,是吗?
SherylHohman '17

4
@SherylHohman,您也可以尝试自己运行该命令,看看是否
有用

2
不要忘了人们经常使用圆括号来进行符合PEP 8的隐式行继续操作,也不要忘记元组不是由括号定义的,而是由逗号的存在定义的(元组与括号无关,除了用于运算符优先级)。
Cowbert

4
assert (2 + 2 = 5), "Houston we've got a problem"不会起作用...但是与assert语句无关,这很好。您的状况不起作用,因为它不是状况。错过了一秒钟=
n1k31t4

133

正如其他答案所指出的,assert类似于在给定条件不成立时引发异常。一个重要的区别是,如果使用优化选项编译代码,则assert语句将被忽略-O。该文档说,assert expression可以更好地描述为等同于

if __debug__:
   if not expression: raise AssertionError

如果您要彻底测试代码,然后在满意所有断言都不失败的情况下发布优化版本,这将非常有用-当优化打开时,__debug__变量变为False且条件将不再被求值。如果您依靠断言并且没有意识到它们已经消失,那么此功能还可以吸引您。


这是否意味着,如果某个变量或正确的输入(根据编写程序的约定)可能导致程序崩溃,则当用户运行该程序时(假设在用户运行该程序时使用-O标志)程序),您应该改用if Not Error: raise Exception(“ this is a error”)?这样,当用户运行该程序时,该程序仍将显示错误的来源
。–

另一方面,如果您期望程序可能由于错误的逻辑/代码实现(而不是由于与程序用户之间的合同规定的输入)而出错,那么您应该使用assert语句吗?这里的假设是,当程序发布给最终用户时,您正在使用-O标志,因此假定所有错误均已删除。因此,任何错误或程序崩溃都是由于根据合同有效地输入了程序而无法由程序处理的。因此,它应该这样警告用户。
alpha_989

@ alpha_989完全正确。我喜欢将断言视为健全性检查,它只能帮助您作为开发人员确保在开发过程中您认为正确的事实是真实的。
Christopher Shroba

52

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

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

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

如果您的程序没有错误,则这些情况将永远不会发生。但是,如果确实发生了其中一种情况,则程序将因声明错误而崩溃,并确切地告诉您触发了哪个“不可能”条件。这使查找和修复程序中的错误变得更加容易。

这是我写的有关Python断言的教程的摘要:

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


感谢您的文章。有助于理解assert陈述以及何时使用它。我试图理解您在本文中介绍的许多术语。
alpha_989 '18

我以为我会在这里发表评论,这样澄清可能会使更多的人受益。很抱歉,如果这些问题太幼稚。
alpha_989 '18

在您链接的博客中,提供了一个示例,其中提到`assert 0 <= price <= product ['price']`是正确的,但是使用`assert user.is_admin()时,“必须具有管理员特权才能删除” “'而assert store.product_exists(product_id), 'Unknown product id'不是一个很好的做法,因为如果调试被关闭,则user即使不是admin就能删除产品。您认为assert user.is_admin()unrecoverable错误吗?为什么不是这样self-check
alpha_989

如果您认为'user.is_admin()`是用户输入,因此不应该在中使用assert statementprice也不能将其视为用户输入吗?为什么将您视为assert user.is_admin()数据验证而不是assert price
alpha_989

1
@LaryxDecidua不,您可以在我的网站上阅读它,该教程是公开可用的。如果您对新闻通讯不感兴趣,请点击逃逸按钮或单击小“ x”符号。希望这会
有所

51

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

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

>>> 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


那么这是否意味着我们可以在assert(2> 5)之类的情况下检入代码并引发错误,否则会继续吗?

20
丢掉括号,断言不是函数。
pillmuncher 2014年

2
丢掉父母比看起来更重要。见下文
Evgeni Sergeev

6
Assert实际上可以追溯到Turing(早于“合同”),当时他写了最早的论文之一,关于程序员如何解决创建正确程序的艰巨任务。由于所有程序员都可以从熟悉他的工作中受益,因此找到论文留给读者练习。:-) turingarchive.org
罗恩·伯克

17

从文档:

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

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


我喜欢这个评论,因为它只是很清楚地解释了什么。我的问题是“如果我编写了适当的单元测试,为什么需要断言”?这些东西不会在生产中运行。
dtc

17

assert语句有两种形式。

简单形式assert <expression>相当于

if __debug__:
    if not <expression>: raise AssertionError

扩展形式assert <expression1>, <expression2>相当于

if __debug__:
    if not <expression1>: raise AssertionError, <expression2>

16

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

>>> 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!
>>> 

1
同样,断言通常可以在单元测试程序中使用。 stackoverflow.com/questions/1383/what-is-unit-testing
panofish 2014年

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

6

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

例如:

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

4

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

当您执行以下操作时:

assert condition

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

在Python中,assertexpression等效于:

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语句使用两个条件。因此,千万不能使用括号englobe他们作为一个显而易见的建议。如果您这样做:

assert (condition, message)

例:

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

您将以代表元组的第一个参数运行assert带有的a (condition, message),这是因为Python中的非空元组始终为True。但是,您可以单独进行而不会出现问题:

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程序员通常在没有用户直接交互的库或模块上使用an 。


3

正如在C2 Wiki上简要概述的那样:

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

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

如果您的断言失败了,这将向您(或您的后继者)发出警报,提醒您在编写程序时对程序的理解是错误的,并且可能包含错误。

有关更多信息,John Regehr在“ Assertions”中有一篇精彩的博客文章,该文章也适用于Python assert语句。


2

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

确保您输入的保留关键字是否作为字符串输入。


2

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

假设有一个函数可以计算折扣后的商品价格:

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

在这里,Discounted_price永远不能小于0且大于实际价格。因此,如果违反了上述条件,则assert会引发Assertion Error,这将有助于开发人员识别出某些不可能的事情发生了。

希望能帮助到你 :)


2
assert在调试上下文中很有用,但不应依赖于调试上下文之外。
FluxIX

2

我的简短解释是:

  • assertAssertionError如果expression为false,则引发,否则继续执行代码,如果有逗号,则为AssertionError: whatever after comma,并且代码如下:raise AssertionError(whatever after comma)

有关此的相关教程:

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


答案提供了如何使用an的信息assert,但没有提供何时使用(或不使用)an的信息assert;还指出,一个assert可以禁用如果__debug__IS False将是有益的。
FluxIX

1

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

例如,假设self.object1.object2是一个MyClass对象。

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

0

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

我不会重复有关关联消息,括号或-O选项和__debug__常量的内容。另请查阅文档以获取第一手信息。我将重点关注您的问题:的用途是assert什么?更准确地说,何时(何时不该使用)assert

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

最有趣的,在我脑海里,使用的assert是由灵感 合同编程为[面向对象的软件建设]由B.迈耶描述( https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction% 2C_2nd_Edition )并以[Eiffel编程语言](https://en.wikipedia.org/wiki/Eiffel_ (programming_language )实施。您不能使用该assert语句通过合同完全模拟编程,但是保持意图很有趣。

这是一个例子。想象一下,您必须编写一个head函数(例如headHaskell中的[ 函数]( 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。这很重要,因为an AssertionError并不是任何运行时错误:它表示违反规范。我想要警告,但出现错误。幸运的是,我可以禁用该检查(使用该-O选项),但后果自负。我会做到的,崩溃真的很昂贵,并且希望最好。想象一下,我的程序嵌入在穿过黑洞的宇宙飞船中。我将禁用断言,并希望该程序足够健壮,以免崩溃的时间尽可能长。

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

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

您不会拥有像Eiffel那样复杂的功能,但是可以提高程序的整体质量。


总而言之,该assert语句是检测这种不应该发生的情况的便捷方法。违反规范(例如,向传递一个空列表head)是头等舱,这种情况不应该发生。因此,尽管该assert语句可用于检测任何意外情况,但这是确保满足规范的一种特权方式。一旦将assert语句插入代码中以表示规范,我们就可以希望您提高了程序的质量,因为将报告错误的参数,错误的返回值,错误的类状态...。


-2

格式:assert Expression [,arguments]当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!    

-2
def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

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


1
这将起作用,但是据我了解,断言不应用于检查用户输入,因为可以在运行时将其关闭。如果您确实要强制执行或验证用户输入,if not user_key: raise ValueError()请在此处使用“ 检查最后2个段落”:wiki.python.org/moin/UsingAssertionsEffectively
alpha_989 '18

assert不应用于输入验证,因为如果__debug__为is ,验证将被剥离False。同样将断言用于非调试目的也会导致人们捕获结果AssertionErrors,这会使调试变得困难而不是更少。
FluxIX

-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
>>> 

-4

基本上,assert关键字的含义是,如果条件不成立,则通过assertionerror进行处理,否则例如在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

2
请正确格式化您的代码。另外,这对以前的答案有何改善?
c2huc2hu

我的解释有什么问题吗?
ujjwal_bansal

您的解释不会为现有答案添加任何内容,语法不佳也很难阅读。如果您正在寻找要回答的问题,请考虑浏览新的问题提要。
c2huc2hu

提供的答案确实回答了如何使用assert,但没有回答何时使用(或不使用)assert
FluxIX
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.