为什么当“if not []”成功时,“[] == False”求值为False?

36

我之所以问这个问题,是因为我知道检查列表是否为空的Pythonic方式如下:

my_list = []
if not my_list:
    print "computer says no"
else:
    # my_list isn't empty
    print "computer says yes"

将打印计算机说不等。因此,这让我将[]False的真值进行比较; 但是,如果我尝试“直接”比较[]和False,则会得到以下结果:

>>> my_list == False
False
>>> my_list is False
False
>>> [] == False
False

这里发生了什么?我感觉自己漏掉了一些非常明显的事情。

在技术方面,可能是由于缺少必要的信息或者对特定领域的知识不够了解导致的。需要进一步了解和学习相关知识才能理解。


4
这是一种很棒的设计,因为它能够让程序员不再使用 if variable == True: 这个条件语句。正确的做法应该是 if variable is True:(确切地说是 True,而不是其他任何值——在大多数情况下并不是最佳方式),或者是 if variable(表示它为真)。 - Casey Kuball
4个回答

60

if语句在布尔上下文中评估所有内容,就像存在对bool()内置函数的隐式调用。

以下是您实际检查if语句将如何评估内容的方法:

>>> bool([])
False
>>> bool([]) == False
True

请参见Truth Value Testing文档,空列表被视为false,但这并不意味着它们等同于FalsePEP 285还提供了一些关于为什么以这种方式实现的优秀信息,请参见“已解决问题”部分中的最后一个项目,特别是处理x == Truex == False的部分。对我来说最有说服力的方面是==通常是可传递的,因此a == bb == c意味着a == c。因此,如果按照您的期望方式,[] == False为true且'' == False为true,则可能会认为[] == ''应该为true(即使在没有隐式类型转换的语言中显然不应该)。

21
“即使显然不应该,JavaScript。” - Christian Mann

14

空容器在布尔上下文中被认为是“假”,也就是说它们在布尔上下文中会被评估为False。这并不意味着它们与常量False相等。

换句话说,以下语句的结果是True

bool([]) == False
对象的真值由其__nonzero__()__len__()方法决定。(在Python 3中,__nonzero__()已重命名为__bool__()。)容器具有一个__len__()方法,因此当它们包含任何内容时它们是真实的,当它们为空时它们是虚假的。
顺便说一句,如果空容器字面上等于False,那么任何空容器都将等于任何其他空容器:例如,{} == "" 将是True。这根本就没有任何意义!
然而,让你大吃一惊的是,以下语句是True:
False == 0

这是因为在Python中,布尔值是整数的一个子类,而False基本上只是一个被以稍微不同的方式打印出来的零。


7
在Python中,内置类型有一个真值(truth value),可以测试它们是否为真。请参阅“Truth Value Testing”(http://docs.python.org/library/stdtypes.html#truth-value-testing)。
这与说“object == False”不同,后者实际上是进行值测试(相等测试)。它使用对象的“__eq__()”方法来确定它们的值是否相等。

我个人认为这是最有用的答案。真实性是一个有趣的概念,可能会导致一些不直观的后果。以JavaScript及其底部值为例。 - dwerner
1
@dwerner:是的,我同意。当我说 if object: 时,我只是尝试思考它是否具有内容。 - jdi

3

在你的示例中,not运算符会将你的列表转换为布尔值。尝试这样做:

>>> not []
True

>>> not [1]
False

"

is"和 "=="不进行类型转换。

"

3
这是一个非常好的观点,即not运算符将其转换为布尔值,但你弄反了。(not []) == True(not [1]) == False - Andrew Clark

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