Python 的 in (__contains__) 运算符返回一个布尔值,其值既不是 True 也不是 False

问题描述

正如所料,1 不包含在空元组中

As expected, 1 is not contained by the empty tuple

>>> 1 in ()
False

但是返回的False值不等于False

>>> 1 in () == False
False

换个角度看,in 运算符返回一个 bool,它既不是 True 也不是 False:

Looking at it another way, the in operator returns a bool which is neither True nor False:

>>> type(1 in ())
<type 'bool'>
>>> 1 in () == True, 1 in () == False
(False, False)

但是,如果原始表达式被括号括起来,则正常行为会恢复

However, normal behaviour resumes if the original expression is parenthesized

>>> (1 in ()) == False
True

或者它的值存储在一个变量中

or its value is stored in a variable

>>> value = 1 in ()
>>> value == False
True

在 Python 2 和 Python 3 中都观察到了这种行为.

This behaviour is observed in both Python 2 and Python 3.

你能解释一下发生了什么吗?

Can you explain what is going on?


解决方案

您遇到了比较运算符链接;1 in () == False not 表示 (1 in ()) == False.

You are running into comparison operator chaining; 1 in () == False does not mean (1 in ()) == False.

相反,比较是链式的,表达式的真正含义是:

Rather, comparisons are chained and the expression really means:

(1 in ()) and (() == False)

因为 (1 in ()) 已经为假,链式表达式的后半部分被完全忽略(因为 False and something_else 返回 False 无论 something_else 的值是什么).

Because (1 in ()) is already false, the second half of the chained expression is ignored altogether (since False and something_else returns False whatever the value of something_else would be).

请参阅比较表达式文档:

比较可以任意链接,例如,x <y <= z 等价于 x <y 和 y <= z,除了 y 只计算一次(但在这两种情况下,当 x 时根本不计算 z; y 被发现为假).

Comparisons can be chained arbitrarily, e.g., x < y <= z is equivalent to x < y and y <= z, except that y is evaluated only once (but in both cases z is not evaluated at all when x < y is found to be false).

作为记录,<, >, ==, >=, <=!=isis notinnot in 都是比较运算符(不推荐使用的 <> 也是如此).

For the record, <, >, ==, >=, <=, !=, is, is not, in and not in are all comparison operators (as is the deprecated <>).

一般来说,不要与布尔值进行比较;只需测试表达式本身.如果您有 需要针对布尔文字进行测试,至少使用括号和 is 运算符、TrueFalse是单例,就像 None:

In general, don't compare against booleans; just test the expression itself. If you have to test against a boolean literal, at least use parenthesis and the is operator, True and False are singletons, just like None:

>>> (1 in ()) is False
True

当涉及整数时,这会变得更加混乱.Python bool 类型是 int1 的子类.因此,False == 0 为真,True == 1 也是如此.因此,您可以想象创建看起来很正常的链式操作:

This gets more confusing still when integers are involved. The Python bool type is a subclass of int1. As such, False == 0 is true, as is True == 1. You therefor can conceivably create chained operations that almost look sane:

3 > 1 == True

是真的,因为 3 >11 == True 都是真的.但表达式:

is true because 3 > 1 and 1 == True are both true. But the expression:

3 > 2 == True

是假的,因为 2 == True 是假的.

is false, because 2 == True is false.

1 bool 由于历史原因是 int 的子类;Python 并不总是像 C 那样具有 bool 类型和具有布尔含义的重载整数.将 bool 设为子类可以让旧代码继续工作.

1 bool is a subclass of int for historic reasons; Python didn't always have a bool type and overloaded integers with boolean meaning just like C does. Making bool a subclass kept older code working.

相关文章