在Python中过度使用“is”而非“==”的风险

如果你已经使用Python一段时间了,可能在代码中使用过is==。它们看起来相似,读起来也很像。但在底层,它们的功能却截然不同。当你本意是使用==时却使用了is,可能会导致微妙而棘手的错误,这些错误非常难以追踪。

is==之间有什么区别?

  • == 检查两个值是否相等。
  • is 检查两个变量是否指向内存中的同一个对象。

这里有一个简单的方法来记住它:

👉 == → “这些东西看起来一样吗?”

👉 is → “这些东西真的是同一个对象吗?”

快速示例

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)  # True: 内容相同
print(a is b)  # False: 内存中的对象不同

尽管 ab 包含相同的列表值,但它们不是同一个对象。Python 创建了两个独立的列表。

 

危险的地方

问题出现在开发者假设 is 的行为与 == 相同,或反之,尤其是因为有时 is 由于 Python 的内部优化而“意外”工作。

 

示例 1:字符串

x = "hello"
y = "hello"

print(x == y)  # True

print(x is y)  # True? ...有时是

对于 is 来说,这可能是 True,因为 Python 会“驻留”(重用)短字符串以节省内存。但请看这个:

a = "hello world! this is a very long string"
b = "hello world! this is a very long string"

print(a == b)  # True
print(a is b)  # False

突然间,is 不再有效,尽管字符串是相等的。为什么?因为 Python 没有对较长的字符串进行驻留。在这里依赖 is 会导致不稳定、不一致的结果,这些结果取决于你无法控制的因素,比如字符串长度或 Python 实现。

 

示例 2:整数

Python 还缓存了介于 -5256 之间的小整数。

x = 256
y = 256

print(x is y)  # True

a = 257
b = 257

print(a is b)  # False

编写一些“通过”某些测试但在生产环境中失败的代码是很容易的。这些错误在后期调试时几乎是不可能的。

 

那么,什么时候应该使用 is

使用 is 是有其合理用途的。但这些用途是特定且罕见的。

在检查单例对象时使用 is

例如:

if my_var is None:
    ...

这是检查 None 的正确方式,因为 None 是一个单例。在 Python 中只有一个 None 对象。

其他有效的情况:

    • my_obj is True
    • my_obj is False

但即使对于 TrueFalse,在数据密集型代码(例如 pandas、NumPy)中,使用 == 通常更安全,因为这些库重新定义了什么是“真值”。

 

真实世界的错误场景

以下是我见过的一些真实错误:

 

错误 1:循环中的错误比较

for item in my_list:
    if item is "done":  # 哎呀

这可能对某些字符串有效,但对其他字符串则会静默失败。正确的检查是:

for item in my_list:
    if item == "done":
        break

错误2:数据验证中的假阴性

user_input = input("请输入 yes 或 no: ")

if user_input is "yes":  # 即使输入为 'yes' 也可能失败
    print("确认!")

你可能永远不会知道这个失败,除非你的用户输入 "yes" 但没有任何反应。

 

错误 3:不可靠的条件逻辑

x = 1000
y = 10 * 100

if x is y: # 错误!即使值相同
do_something()

这将静默地不执行 do_something(),即使大多数人会说“1000等于1000。”

 

何时使用哪一个?

  • 除非你100%确定是在检查身份,否则请使用 ==
  • 仅在检查 None 或与哨兵对象比较时使用 is
  • 不要依赖Python的内部优化,如字符串驻留或小整数缓存。这些是实现细节,可能在不同版本或平台之间发生变化。
操作 使用 ==? 使用 is?
值相等
对象身份
None 比较
与常量比较(例如,字符串,整数)
编写可靠、可移植的代码 ❌(除了 None

更多