为什么不使用 "is" 比较来代替基本类型的“==”?

Why isn't "is" comparison used in place of "==" for primitive types?

当我使用 Pytest 进行 Python 格式化时,它会抱怨做类似的事情:

>>> assert some_function_ret_val() == True
E712 comparison to True should be 'if cond is True:' or 'if cond:'

并且想要:

assert some_function_ret_val() is True

我知道 True/False/None 只能有一个副本,但我认为所有基元都是不可变类型。

在什么情况下“==”和"is"比较原始类型会有所不同?

否则,为什么“==”成为比较任务的常态?

我发现这个 Whosebug post 讨论了与非原始类型的比较,但我似乎无法找到为什么 "is" 比较对原始类型可能很危险的原因。 Comparison with boolean numpy arrays VS PEP8 E712

如果只是约定俗成,我会认为 "is" 比“==”更易读,但我觉得可能会有一些疯狂的边缘情况,其中可能有多个原语副本类型。

Python 没有原始类型。 Python 中的所有内容都是对象。

通常,您唯一应该使用 is 的地方是 language-guaranteed 单例,例如 TrueFalseNone 或者说出于调试目的,您实际上想要检查对象身份。

在所有其他情况下,如果您使用 is 表示相等(例如 peep-hole 优化器和字符串驻留)。相等运算符是 ==,应该在这些情况下使用。虽然 Python 解释器通常会优化不可变类型,但当您表示相等时,您仍然不应依赖标识,因为大多数情况下,这不是 语言保证.

例如,在 CPython 3.7 上,您可以 "safely" 忍不住选择使用 is 来比较 小整数 因为它们被缓存了,所以这是一个实现细节,应该 依赖。这可以在 Python 3.9 或任何时候自由更改。另外,请参阅@user2357112 关于缓存的小整数甚至不一定安全的评论!重申一下:这不是语言保证 - 它是如何实施的 side-effect。

同样,它只适用于小整数,[-5, 256] 所以:

>>> def add(a, b): return a + b
...
>>> 16 is add(8, 8)
True
>>> 1000 is add(500, 500)
False

注意,我把实际的加法放在一个函数中,解释器经常优化不可变文字和算术表达式:

>>> 1000 is (500 + 500)
True

但现在应该很明显为什么不能依赖它了。

另一个适合使用 is 进行 "equalityish" 比较的例子是比较 enum 类型,保证是单例:

import enum
class Color(enum.Enum):
    RED = 1
    BLUE = 2

RED = Color.RED
BLUE = Color.BLUE

print(Color(1) is RED)