首页 > 解决方案 > Python中的“0就是0”总是“真”吗?

问题描述

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

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

对于代码0 is 0

is我理解警告,并且知道和之间的区别==

但是,我也知道 CPython 会缓存小整数的对象并在其他情况下共享它。(出于好奇,我刚刚再次检查了代码标头)。小整数缓存在tstate->interp->small_ints. 中0,并且1更特别,全局存储在_PyLong_Zeroand中_PyLong_One。所有新创建的ints 都是通过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 数组,你真的会在这里节省一个(可能成本高昂的)操作。

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

当然,您可以使用sum1c代替sum1a. 然而,sum1a更短。所以这个更好看?

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

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

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

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

标签: pythonpython-3.xcpythonpython-internals

解决方案


不,不是。举个例子,Python 的Rust 实现返回False

>>>>> 0 is 0
False

这并没有错,尽管我希望这会在未来的版本中改变(它有!)。

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


推荐阅读