在 Python 中,“0 is 0”总是“True”吗?

Is `0 is 0` always `True` in Python?

Python 3.8(或 CPython 3.8?)添加了警告

SyntaxWarning: "is" with a literal. Did you mean "=="?

代码 0 is 0.

我理解警告,我知道is==之间的区别。

不过,我也知道 CPython 缓存小整数的对象并在其他情况下共享它。 (出于好奇,我又 checked the code (header)。 小整数缓存在 tstate->interp->small_ints 中。 01更加特殊,全局存储在_PyLong_Zero_PyLong_One中。 int 的所有新创建都是通过 PyLong_FromLong 并且首先检查它是否是一个小整数并缓存。)

鉴于此背景,如果您知道您有一个 int 对象,您可以说检查 x is 0 应该是安全的,对吧?另外,您可以推导出 0 is 0 应该始终是 True,对吗?或者这是 CPython 的实现细节,而其他解释器不遵循这个?哪个解释器不遵循这个?

尽管有这个更一般的问题(我只是好奇),请考虑这个更具体的(示例)代码:

def sum1a(*args):
    y = 0
    for x in args:
        if y is 0:
            y = x
        else:
            y = y + x
    return y

对比:

def sum1b(*args):
    y = 0
    for x in args:
        if y == 0:
            y = x
        else:
            y = y + x
    return y

对比:

def sum1c(*args):
    y = None
    for x in args:
        if y is None:
            y = x
        else:
            y = y + x
    if y is None:
        return 0
    return y

对比:

def sum2(*args):
    y = 0
    for x in args:
        y = y + x
    return y

我有时更喜欢 sum1* 而不是 sum2 的原因是,根据库的不同,sum1* 确实可以更有效率。例如。如果参数是一个 Numpy/TensorFlow/PyTorch 数组,你真的会在这里保存一个(可能代价高昂的)操作。

我更喜欢 sum1a 而不是 sum1b 的原因是 sum1b 会在某些输入上中断。例如。如果输入是 Numpy 数组,这将不起作用。

当然,您可以使用 sum1c 而不是 sum1a。但是,sum1a 更短。所以这个更好看?

如果原始问题的答案是这应该始终有效,并且如果您同意 sum1a 是最佳选择,那么您将如何消除警告?有简单的解决方法吗?总的来说,我可以看到警告是有用的。所以我不想完全禁用它。我只想为这个特定的语句禁用它。

也许我可以将其包装在一个函数中:

def is_(a, b):
    return a is b

然后只需使用 if is_(y, 0): ...。这行得通吗?这是个好主意吗?

不,不是。例如 Rust implementation for Python returns False:

>>>>> 0 is 0
False

这并没有错,尽管我希望这会在未来的版本中发生变化(它已经发生了!)。

is calls id 唯一的规定是返回的 id 对于给定对象是唯一且恒定的。数字(0 此处)的源代码表示是否映射到不同的对象取决于实现来定义。