Python的is与==:先分清对象身份和内容相等
在 Python 中,比较两个变量时,经常会看到 == 和 is。两者的写法很短,但回答的问题不同。日常判断两个列表、字符串或数字是否相等,通常使用 ==;判断两个变量是否指向同一个对象,才使用 is。先明确比较目的,比根据一次运行结果猜测规则更可靠。
以列表为例,分别创建 a = [1, 2] 和 b = [1, 2]。它们的元素相同,因此 a == b 的结果为 True;但这两次列表创建得到的是不同对象,a is b 的结果为 False。这里的结果说明,内容相同,并不要求两个变量引用同一个对象。
再执行 c = a。这个赋值没有复制列表,而是让 c 和 a 引用同一个列表,所以 c is a 为 True。通过 c 追加元素 3 后,a 的内容也变成 [1, 2, 3];独立创建的 b 仍然是 [1, 2]。排查“修改一个变量,另一个变量也变了”的问题时,应先检查是否共享了可变对象,而不是把内容比较当成复制关系的证明。
对于 None,判断变量是否为这个特殊值,常见写法是 value is None 或 value is not None。这样表达的就是对象身份检查。不要把这一写法直接推广到数字和文本:判断状态字符串是否等于某个业务值,应使用 ==;判断金额是否等于零,也应使用 ==。不要依赖解释器可能进行的对象复用来决定业务逻辑。
身份检查还可以用于自己创建的专用标记。例如在读取配置时,字段不存在与字段明确设为 None,可能需要不同处理。可以先创建一个 marker = object(),然后用配置字典的 get 方法读取字段,并把 marker 作为缺省返回值。读取结果 is marker 时,表示字段缺失;结果 is None 时,表示字段存在且值为空。这要求始终复用同一个 marker,不能在比较时重新创建另一个 object()。
另一个容易混淆的地方是真值判断。如果只是判断容器是否非空,通常直接写 if items。items is True 检查的是它是否就是 True 这个布尔对象,并不能替代容器的真值判断。同样,数值比较中的相等也不意味着类型一致。在本地验证中,布尔值 True 与整数 1 使用 == 比较为相等,但它们并不是同一个对象。需要严格限制数据类型时,应把类型校验作为单独的要求。
对于自定义类,还要留意相等规则可能由类的比较方法定义。业务对象可以根据编号、字段组合等规则判断相等,因此不能简单地把 == 理解成“比较内存地址”。is 的用途则一直是身份判断。编写对象比较代码时,应先看清对象提供的比较语义。
这次在本地检查了独立列表相等、列表身份不同、赋值共享对象、追加元素的影响、None 判断,以及专用标记区分缺失和空值等情况。实际排错时,可以先问三个问题:我在比较内容、判断同一个对象,还是判断真值?将这三个问题分开,比较表达式通常就能写得清楚。
参考:Python 语言参考 Expressions 中的 Identity comparisons 与 Value comparisons。
https://docs.python.org/3/reference/expressions.html#comparisons
- 点赞
- 收藏
- 关注作者
评论(0)