带或不带括号的"assert"语句

145

以下是四个简单的assert调用示例:

>>> assert 1==2
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert 1==2, "hi"
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError: hi

>>> assert(1==2)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AssertionError

>>> assert(1==2, "hi")

注意,最后一个示例不会引发错误。调用assert时使用或不使用括号会导致这种行为差异,你能解释一下原因吗?我的做法是使用括号,但上述内容表明我不应该这么做。


感谢提供有用的答案。关键字和内置函数之间的区别似乎很微妙。这里是一个关键字列表,我认为应该省略括号:http://docs.python.org/reference/lexical_analysis.html#keywords - new name
2
一个区别是你可以重新定义内置函数,但不能使用关键字这样做(前者并不是一个好主意)。 - new name
这不是函数与关键字的区别,而是函数调用语句的区别。(例如 - print曾经是一个语句,并且可以在没有括号的情况下工作)。 - Tomasz Gandor
6个回答

162
最后一个assert会在通过完整的解释器而不是IDLE运行时给出警告(SyntaxWarning: assertion is always true, perhaps remove parentheses?)。 因为assert是关键字而不是函数,实际上您将元组作为第一个参数传递,并省略了第二个参数。
请记住,非空元组计算为True,并且由于断言消息是可选的,因此当您编写assert(1==2, "hi")时,实际上调用了assert True

12
assert (1==2)之所以没有报错是因为在单个表达式的括号内不会自动创建元组;如果你写成assert (1==2,),那么就会得到与 #4 相同的结果。同样的情况也会出现在print ('foo', 'bar')中,而不是print 'foo', 'bar';你将看到输出的结果变成了一个元组。 - Michael Mrozek
值得进一步强调的是,形如assert(test, message)的语句可能是错误的,而且肯定会令人困惑。不要使用括号! - tcarobruce
35
那么,根据PEP8规范,缩进长的assert语句的正确方式是什么?这似乎是不可能的。 - stantonk
9
好的,我会尽力完成您的翻译要求。以下是需要翻译的内容:https://dev59.com/3GQo5IYBdhLWcg3wbe1K如何格式化符合 PEP 8 标准的 Python assert 语句。 - Jonatan

53

如果您之所以在那里放括号是因为您想要一个多行断言,那么另一种选择是在该行末尾放一个反斜杠,像这样:

foo = 7
assert foo == 8, \
    "derp should be 8, it is " + str(foo)

打印:

AssertionError: "derp should be 8, it is 7

为什么Python中的assert要和其他所有东西都不同:

我认为Python的理念是程序应该自我纠正,而不必担心特殊标志来开启断言。关闭断言的诱惑太大了,因此它正在被弃用。

我分享您对于Python中assert具有与所有其他Python编程结构不同的语法而感到烦恼的情绪,而这种语法从Python2到Python3又再次发生了变化,从Python 3.4变化到了3.6。 这使得assert语句在任何版本之间都不能向后兼容。

这是一个暗示,表明assert是Python的三等公民,它将在Python4中被完全删除,并且当然还会在Python 8.1中被删除。


7
有没有相关文档说明我们应该使用什么替代assert?Assert这个名字对于验证似乎非常合理,并且它具有所需的行为,例如在出现错误时显示特殊消息。 - AnneTheAgile
我在Python 8.1中再次看到assert被移除,笑翻了。 - undefined
@YPOC 这些密码子的原始创作者选择了蒙提·派森的《奶酪店》小品,他们向适当的人提供了解决计算机科学中的命名问题的计划所需的一切,正如Knuth/Richie所描述的那样。 - undefined

33

你可以这样不使用 \ 来打破断言语句:

foo = 7
assert foo == 8, (
    'derp should be 8, it is ' + str(foo))

或者,如果您有更长的消息:

foo = 7
assert foo == 8, (
    'Lorem Ipsum is simply dummy text of the printing and typesetting '
    'industry. Lorem Ipsum has been the industry\'s standard dummy text '
    'ever since the 1500s'
)

2
有趣的想法。我讨厌使用反斜杠进行换行,这是将assert包装在实用函数中的替代方法(这是我的解决方案)。 - Tomasz Gandor

20

assert 1==2, "hi" 被解析为 assert 1==2, "hi",其中"hi"是关键字的第二个参数。因此它能正确地给出错误提示。

assert(1==2) 被解析为 assert (1==2),这与 assert 1==2 相同,因为括号只是单个项目时不会创建元组,除非有一个尾随逗号,例如 (1==2,)

assert(1==2, "hi") 被解析为 assert (1==2, "hi"),这不会产生错误,因为非空元组 (False, "hi") 不是 false 值,并且没有为关键字提供第二个参数。

你不应该使用括号,因为在 Python 中 assert 不是函数,而是关键字。


1
以下内容引用自python文档
断言语句是向程序插入调试断言的一种便捷方式:
assert_stmt ::= "assert" expression ["," expression]
简单形式 assert expression 等同于:
if __debug__: if not expression: raise AssertionError 扩展形式 assert expression1, expression2 等同于:
if __debug__: if not expression1: raise AssertionError(expression2)
因此,在这里使用括号时,您正在使用简单形式,并且表达式被评估为元组,当转换为布尔值时始终为True。

0

assert语句,无论是否使用下面所示的括号,都是相同的:

assert (x == 3)

assert x == 3

而且,其他语句,例如ifwhilefordel,无论是否带有括号,如下所示,也是相同的:


if (x == "Hello"):

if x == "Hello":

while (x == 3):

while x == 3:

for (x) in (fruits):

for x in fruits:


del (x)

del x

此外,基本上,我迄今见过的大部分示例Python代码在使用assertifwhilefordel语句时都没有使用括号,所以我更倾向于不使用括号

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接