1311

我一直在阅读一些源代码,并在几个地方看到了assert.

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

4

22 回答 22

1519

assert语句几乎存在于每种编程语言中。它有两个主要用途:

  1. 它有助于在您的程序早期发现问题,原因是明确的,而不是稍后在某些其他操作失败时。例如,Python 中的类型错误可能会经过几层代码,然后才能真正Exception提早发现 if not catch。

  2. 它作为其他开发人员阅读代码的文档,他们看到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在优化模式下运行时, where __debug__is False, assert 语句将被忽略。只需传递-O标志:

python -O script.py

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

于 2011-02-28T13:15:33.593 回答
554

注意括号。正如在其他答案中所指出的那样,在 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在布尔上下文中求值。

于 2015-06-11T02:15:30.310 回答
169

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

if __debug__:
   if not expression: raise AssertionError

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

于 2011-02-28T14:10:37.460 回答
86

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

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

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

如果您的程序没有错误,这些情况将永远不会发生。但是,如果其中一个确实发生了,程序将崩溃,并显示一个断言错误,告诉您确切触发了哪个“不可能”条件。这使得跟踪和修复程序中的错误变得更加容易。

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

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

于 2017-01-18T14:04:46.110 回答
56

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

您可以在交互式 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

于 2011-02-28T13:18:19.973 回答
24

来自文档:

断言语句是将调试断言插入程序的便捷方式

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

于 2011-02-28T13:16:38.100 回答
21

assert 语句有两种形式。

简单形式 ,assert <expression>等价于

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

扩展形式 ,assert <expression1>, <expression2>等价于

if __​debug__:
    if not <expression1>: raise AssertionError(<expression2>)
于 2013-07-10T01:21:45.477 回答
18

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

>>> 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!
>>> 
于 2014-02-19T16:52:57.763 回答
8

这是一个简单的示例,将其保存在文件中(比如说 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
于 2014-02-17T14:54:52.543 回答
8

正如C2 Wiki上简明扼要的总结:

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

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

如果您的断言失败,这会提醒您(或您的继任者)您在编写程序时对程序的理解是错误的,并且它可能包含错误。

有关更多信息,John Regehr 有一篇关于使用断言的精彩博客文章,它也适用于 Pythonassert语句。

于 2018-12-08T10:14:25.393 回答
8

assert语句几乎存在于每种编程语言中。它有助于在您的程序早期发现问题,原因是明确的,而不是稍后作为某些其他操作的副作用。他们总是期待一个True条件。

当您执行以下操作时:

assert condition

您是在告诉程序测试该条件并在它为假时立即触发错误。

在 Python 中,assert表达式, 等价于:

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

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

1.括号

您可能已经注意到,该assert语句使用两个条件。因此,不要使用括号将它们作为一个明显的建议。如果您这样做:

assert (condition, message)

例子:

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

您将使用assert表示(condition, message)元组的 a 作为第一个参数运行,这会导致 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程序员通常在没有用户直接交互的库或模块上使用。

于 2019-04-20T13:21:53.687 回答
7

如果断言后的语句为真,则程序继续,但如果断言后的语句为假,则程序出错。就那么简单。

例如:

assert 1>0   #normal execution
assert 0>1   #Traceback (most recent call last):
             #File "<pyshell#11>", line 1, in <module>
             #assert 0>1
             #AssertionError
于 2014-11-01T05:05:43.010 回答
5

在 Pycharm 中,如果你使用assertwithisinstance来声明对象的类型,它会让你在编码时访问父对象的方法和属性,它会自动完成。

例如,假设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
于 2020-05-11T17:05:30.717 回答
3

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

如果您输入的是保留关键字,请确保将其作为字符串输入。

于 2015-07-16T03:51:02.987 回答
3

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,这有助于开发人员识别不可能发生的事情。

希望能帮助到你 :)

于 2018-04-15T17:13:52.317 回答
3

我的简短解释是:

  • assert如果表达式为假,则引发AssertionError,否则继续代码,如果有逗号,不管它是什么AssertionError: whatever after comma,代码就像:raise AssertionError(whatever after comma)

关于这个的相关教程:

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

于 2018-09-23T05:55:31.450 回答
2

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

我不会重复有关关联消息、括号或-O选项和__debug__常量的内容。还要检查文档以获取第一手信息。我将专注于您的问题:有什么用assert?更准确地说,什么时候(什么时候不)应该使用assert

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

在我看来,最有趣的使用assert是受 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函数(例如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。这很重要,因为 anAssertionError不是任何运行时错误:它表示违反规范。我想要一个警告,但我得到一个错误。幸运的是,我可以禁用检查(使用-O选项),但风险自负。我会这样做,崩溃真的很昂贵,希望最好。想象一下,我的程序嵌入在一个穿越黑洞的宇宙飞船中。我将禁用断言,并希望程序足够健壮,不会尽可能长时间地崩溃。

这个例子只是关于前置条件,你可以assert用来检查后置条件(返回值和/或状态)和不变量(类的状态)。请注意,检查后置条件和不变量assert可能很麻烦:

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

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


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

于 2020-04-29T18:26:04.370 回答
1

Python 中的assert关键字引发一个AssertionErrorifassert关键字后面的代码是False. 如果没有,它会继续,因为什么都没发生。

示例 1

a = 5
b = 6

assert a == b

输出:

AssertionError

这是因为,显然a不等于b。如果您想Exception在代码中引发 an,这将特别有用。

def get_dict_key(d, k):
    try:
        assert k in d
        return d[k]
    except Exception:
        print("Key must be in dict.")

上面的例子实际上没用,但请记住,它主要用于调试目的,因此您可以跟踪您的错误。

于 2017-07-26T17:19:01.663 回答
1

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

语法: 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. 它几乎存在于所有编程语言中
于 2020-10-28T07:18:24.607 回答
-2

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

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!    
于 2014-12-26T15:16:43.687 回答
-4
def getUser(self, id, Email):

    user_key = id and id or Email

    assert user_key

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

于 2015-03-24T11:54:17.807 回答
-5
>>>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
>>> 
于 2017-04-25T05:04:15.410 回答