12

我正在学习python,但我对以下结果有点困惑。

In [41]: 1 == True
Out[41]: True

In [42]: if(1):
    ...:     print('111')
    ...:     
111

In [43]: ... == True
Out[43]: False <===== why this is False while '1 == True' is True in previous sample

In [44]: if (...): <==== here ... just behaves like True
    ...:     print('...')
    ...:     
...

根据文档...真值为 True。

但是我还是觉得上面的代码有点不一致。

...还有更有趣的事情:

In [48]: 2==True
Out[48]: False <===== why 1==True returns True while 2==True returns False?

In [49]: if(2):
    ...:     print('222')
    ...:     
222
4

4 回答 4

12

您混合了两个概念:相等测试和真值测试。它们在 Python 中是不一样的。

我认为引发这个问题的原因是 Python在你这样做时会进行隐式强制转换if something(它将某物强制转换为bool),但在你这样做时它不会进行隐式强制转换something1 == something2

Python 的数据模型实际上解释了这些操作是如何完成的:

真值检验

  • 它首先检查对象是否实现了该__bool__方法,如果实现了,则使用返回的布尔值。
  • 如果它没有定义__bool__方法,它会查看该__len__方法。如果它被实现,它将使用len(obj) != 0.
  • 如果两者都没有,则考虑该对象True

对于整数,该__bool__方法返回True,除非整数值为0(然后它是False)。

另一方面, Ellipsis 对象(...是 Ellipsis 对象)没有实现__bool____len__所以它总是True

平等测试

相等性测试依赖于两个参数的__eq__方法。它更像是一个操作链:

  • __eq__当第二个操作数作为参数传递时,它检查第一个操作数是否实现。
  • 如果没有,则检查第二个操作数是否__eq__在第一个操作数作为参数传递时实现。
  • 如果不是,则 Python 检查对象身份(如果它们是同一个对象 - 类似于 C 语言中的指针比较)

这些操作的顺序可能会有所不同。1

对于内置的 Python 类型,这些操作是显式实现的。例如integers 实现__eq__CHECK_BINOP确保NotImplemented如果另一个不是integer 则返回。

Ellipsis对象根本没有实现__eq__

因此,当您比较整数和省略号时,Python 将始终回退到对象标识,因此它将始终返回False.

另一方面,booleans 是 egers 的子类,int因此它们实际上是与之比较的(毕竟int它们是另一个)。int布尔值实现为1( True) 和0( False)。所以他们比较相等:

>>> 1 == True
True
>>> 0 == False
True

>>> 1 == False
False
>>> 0 == True
False

尽管源代码可能很难理解,但我希望我能充分解释这些概念(源代码用于 CPython 实现,其他 Python 实现如 PyPy、IronPython 中的实现可能会有所不同!)。重要的外卖信息应该是 Python 在等式检查中不进行隐式转换,并且等式测试与真值测试完全无关。内置类型的实现几乎总是给出合理的结果:

  • 所有数字类型都以某种方式实现相等(浮点数与整数比较,复数与整数和浮点数比较)
  • 并且所有非零且非空的都是truthy.

但是,如果您创建自己的类,则可以根据需要覆盖相等性和真值测试(然后您会散布很多混乱)!


1在某些情况下,顺序会更改:

  1. 如果第二个操作数是第一个操作数的子类,则前两个步骤相反。
  2. 对于某些隐式相等检查__eq__,在调用任何方法之前检查对象身份。例如,当检查某个项目是否在列表中时,即1 in [1,2,3].
于 2017-05-11T23:27:29.353 回答
6

可以测试任何对象的“真实性”

可以测试任何对象的真值,用于 if 或 while 条件或作为以下布尔运算的操作数。以下值被认为是错误的:

  • 没有任何

  • 错误的

  • 任何数字类型的零,例如 0、0.0、0j。

  • 任何空序列,例如,''、()、[]。

  • 任何空映射,例如 {}。

  • 用户定义类的实例,如果该类定义了bool () 或len () 方法,则当该方法返回整数零或 bool 值 False。[1]

所有其他值都被认为是真的——所以许多类型的对象总是真的。

除非另有说明,否则具有布尔结果的操作和内置函数始终返回 0 或 False 表示假,1 或 True 表示真。(重要的例外:布尔运算 or 和 and 总是返回它们的操作数之一。)

所以不难看出if ...会进入分支。Ellipsis对象被考虑true​​。但是,这并不意味着它必须等于True。只是bool(...) == True

if隐式调用bool条件,因此:

if ...:
    # something

将被评估,就好像你写了:

if bool(...):
    # something

和:

>>> bool(...)
True
>>> bool(1)
True
>>> bool(2)
True

但是,这里有一个问题。True等于1False等于0,但这只是因为python中的bool子类integer。

于 2017-05-11T14:56:24.760 回答
1

在 python 中,大多数(全部?)对象都有一个bool值。“具有真值”背后的含义意味着bool(obj)评估为真。

另一方面,在许多情况下(和)True被视为当您执行以下操作时可以看到的:1False0

sum([True, True, False])
# (1 + 1 + 0) -> 2

这就是为什么你得到1 == True-->True

文档中有更明确的解释

布尔值是两个常量对象 False 和 True。它们用于表示真值(尽管其他值也可以被认为是假或真)。在数字上下文中(例如,当用作算术运算符的参数时),它们的行为分别类似于整数 0 和 1

从文档中的类型层次结构本身:

这些代表真值 False 和 True。表示值 False 和 True 的两个对象是唯一的布尔对象。布尔类型是整数类型的子类型,布尔值在几乎所有上下文中的行为分别类似于值 0 和 1,例外是当转换为字符串时,返回字符串“False”或“True” , 分别。

于 2017-05-11T14:54:31.863 回答
1

我相信它在1 == True这里是奇怪的,不是那个... != True

1等于True因为在 Python 中布尔值是整数的子类(因为PEP-285)。看看自己:

>>> issubclass(bool, int)
True
于 2017-05-11T15:01:35.087 回答