Python既不是真也不是假的东西

时间:2009-10-18 12:09:00

标签: python boolean

我刚刚发现了这个:

a = (None,)
print (a is True)
print (a is False)
print (a == True)
print (a == False)
print (a == None)
print (a is None)
if a : print "hello"
if not a : print "goodbye"

产生:

False
False
False
False
False
False
hello

所以既不是,也不等于True或False,但在if语句中作为True。

为什么?

更新:

实际上,我刚刚意识到这并不像我想象的那么模糊。我得到a = 2的相同结果(虽然不是a = 0或a = 1,它们分别被认为等于False和True)

7 个答案:

答案 0 :(得分:13)

我发现这里几乎所有的解释都没有用,所以这是另一个尝试:

这里的混淆是基于“is”,“==”和“if”三种不同的测试。

  • “is”测试身份,即它是否是同一个对象。在这种情况下,显然不是这样。
  • “==”测试值相等,显然唯一具有True和False值的内置对象是True和False对象(除了数字0和1之外,任何数字类型)。

这里有重要的部分:

  • 'if'测试布尔值。这意味着无论你给它什么表达式,它都将被转换为True或False。您可以使用bool()进行相同的操作。并且bool((None,))将返回True。将评估为False的内容列在文档中(由其他人链接)

现在也许这只是在我的头脑中更清楚,但至少我试过了。 :)

答案 1 :(得分:9)

a是一个单成员元组,其结果为Trueis测试对象的身份,因此,您在所有测试中获得False==测试对象的相等性,因此,您再次获得False

if语句中__bool__(或__nonzero__)用于评估对象,对于非空元组,它应返回True,因此得到{{} 1}}。希望能回答你的问题。

修改TrueTrue分别等于False1的原因是因为0类型实现为bool类型的子类。

答案 2 :(得分:2)

python中的内容不一定是TrueFalse中的一个。

当它们用作if / while循环的文本表达式时,它们会转换为布尔值。您无法使用is==来测试他们评估的内容。您使用bool( thing )

>>> a = (None,)
>>> bool(a)
True

另请注意:

>>> 10 == True
False
>>> 10 is True
False
>>> bool(10)
True

答案 3 :(得分:2)

TL; DR:

if==是完全不同的操作。 if检查变量的真值,而==比较两个变量。 is也比较两个变量,但如果两个变量都引用相同的对象,则进行比较。

因此,将变量与TrueFalseNone进行比较以检查其真值是没有意义的。

在变量上使用if时会发生什么?

在Python中,if之类的检查会隐式获取参数的bool。所以

if something:

将(在引擎盖下)执行如下:

if bool(something):

请注意,您不应该在代码中使用后者,因为它被认为不那么pythonic而且速度较慢(因为Python然后使用两个bool s:bool(bool(something)))。 始终使用if something

如果您对CPython 3.6的评估方式感兴趣:

enter image description here

请注意,CPython并未在此处使用hasattr。它会检查type的{​​{1}}是否实现了该方法,但没有通过x方法(__getattribute__会使用该方法)。

在Python2中,该方法称为hasattr而不是__nonzero__

使用__bool__

比较变量时会发生什么

==将检查是否相等(通常也称为“值相等”)。但是,此等式检查不会强制操作数(与其他编程语言不同)。 Python中的值相等是明确实现的。所以你可以这样做:

==

但是,如果任一操作数未实现比较,则>>> 1 == True # because bool subclasses int, True is equal to 1 (and False to 0) True >>> 1.0 == True # because float implements __eq__ with int True >>> 1+1j == True # because complex implements __eq__ with int True 将默认引用比较(==)。这就是原因:

is

因为>>> (None, ) == True False 不支持与tuple的平等,反之亦然。请注意,即使将列表与元组进行比较也是“不受支持的”:

int

如果您感兴趣,这就是CPython(3.6)实现相等的方式(橙色箭头表示操作是否返回>>> [None] == (None, ) False 常量):

enter image description here

这只是粗略正确,因为CPython还检查NotImplementedtype()的{​​{1}}是否实现value1(不经过value2方法!)它被调用(如果存在)或被跳过(如果它不存在)。

请注意,Python2中的行为明显更长(至少如果方法返回__eq__)并且Python 2也支持__getattribute__

使用NotImplemented

比较变量时会发生什么

__cmp__通常称为引用相等比较运算符。如果两个变量都引用完全相同的对象,它只返回is。通常,保持相同值的变量可以引用不同的对象:

is

请注意,CPython使用缓存值,因此有时“应该”为不同实例的变量实际上是同一个实例。这就是为什么我没有使用True(同一行中具有相同值的文字总是相等)以及为什么我不能使用>>> 1 is 1. # same value, different types False >>> a = 500 >>> a is 500 # same value, same type, different instances False 作为示例(因为CPython重新使用值-5)到256)。

但回到你的比较:500 is 500比较引用,这意味着如果两个操作数具有相同的类型和值但它们必须是相同的引用是不够的。鉴于它们甚至没有相同的类型(您将1istuple对象进行比较),bool无法返回NoneType

请注意,isTrueTrue(以及FalseNone)是CPython中的常量和单例。在这些情况下,这不仅仅是一种优化。

答案 4 :(得分:1)

(None,)是一个包含元素的元组,它不是空的,因此在该上下文中不会计算为False。

答案 5 :(得分:1)

因为a=(None,)是包含单个元素None

的元组

使用a=None再试一次,您会看到有不同的结果。

同时尝试a=()这是空元组。其真值为false

答案 6 :(得分:0)

在Python中,可以使用bool函数或__nonzero__ method将所有类型转换为bool()

示例:

  • 序列(列表,字符串,...)在空时转换为False
  • 当整数等于0时,整数将转换为False
  • 您可以通过覆盖__nonzero__()
  • 在自己的类中定义此行为

[编辑]

在您的代码中,使用(None,)语句中的bool()转换元组if。由于它是非空的,因此评估为True