Python中is关键字详细说明,比较的是地址还是值

下面是一篇专门讲 is 等"相等/身份"判断的说明文,会对"到底比的是地址还是值"这个问题展开说明,并顺带讲几个常见容易混淆的运算符和关键字。


一、先说结论:is 比较的是"对象身份",不是值

在 CPython 这种主流实现里,可以粗略理解为:

is 比较的是两个变量是不是同一个对象(同一块内存里的同一个东西)。

常见写法:

python 复制代码
a is b      # 身份比较:是否为同一个对象
a is not b  # 身份不相等

而:

python 复制代码
a == b      # 值比较:值是否相等(由类型的 __eq__ 决定)
a != b      # 值不相等

1. "地址"这个说法该怎么理解?

在 C、C++ 等语言里,你可能会说"比较地址"。

在 Python 层面并不会直接暴露内存地址,但可以用 id(obj) 来理解为"对象身份":

python 复制代码
id(obj)  # 返回一个在该对象生命周期中唯一的整数标识

在 CPython 中,这个 id 通常就是该对象在内存中的地址(实现相关,不是语言保证,但足够帮助理解)。

于是可以理解为:

python 复制代码
a is b       ≈  id(a) == id(b)
a is not b   ≈  id(a) != id(b)

二、is== 的区别:几个典型例子

1. 对于可变对象(list、dict 等)

python 复制代码
a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)  # True,值相等
print(a is b)  # False,不是同一个列表对象

如果你让两者指向同一个对象:

python 复制代码
c = a
print(a == c)  # True
print(a is c)  # True,同一个对象

2. 对于不可变对象(int、str 等)

python 复制代码
x = 1000
y = 1000

print(x == y)  # True,值相同
print(x is y)  # 可能是 False(不同实现/不同场景可能不同)

在 REPL / 小脚本里,x is y 有时会意外变成 True,这涉及常量缓存/驻留(interning),后面会说,但你应该记住:

判断数值、字符串等是否"值相等",始终用 ==,不要指望 is


三、为什么有时候 a is b 会"意外"为 True?

1. 小整数缓存(CPython 的实现细节)

CPython 中对部分小整数做了缓存(通常是 [-5, 256]),以提升性能:

python 复制代码
a = 100
b = 100
print(a is b)   # 在 CPython 中通常是 True(共享同一个小整数对象)

但这是解释器实现细节,不是语言规范保证。你不能依赖这一行为写逻辑。

2. 字符串驻留(interning)

一些字符串也会被复用,尤其是:

  • 标识符形式的字符串(如变量名、函数名)
  • 常量字符串字面量
python 复制代码
s1 = "hello"
s2 = "hello"
print(s1 is s2)  # 在许多情况下是 True,但不能依赖

但一旦涉及拼接、运行时生成,情况就变化了:

python 复制代码
s1 = "he" + "llo"   # 常量折叠,可能仍然是驻留
s2 = "".join(["he", "llo"])

print(s1 == s2)  # True
print(s1 is s2)  # 不一定 True

原则

  • 判断字符串内容是否相同,用 ==
  • 不要写依赖 is 的字符串比较逻辑

四、什么时候应该用 is

1. 与单例对象比较:NoneTrueFalse

Python 里有一些"单例"对象,全局只有一个实例,例如:

  • None
  • True
  • False
  • 某些库中的特定单例(如 sentinel 对象)

判断是否为 None 的推荐写法:

python 复制代码
if x is None:
    ...

而不是:

python 复制代码
if x == None:  # 不推荐
    ...

原因:

  • x == None 会调用 x.__eq__(None),由类型自己决定比较逻辑,可能被重载,甚至返回奇怪的结果
  • x is None 是纯身份比较,更精确表示"是否就是那个唯一的 None 对象"

类似地,当你自己设计一个"特殊标记"对象时,也可以用 is 来判断:

python 复制代码
SENTINEL = object()  # 独特标记

if value is SENTINEL:
    ...

2. 检查对象是否为同一实例

比如你在缓存/池化(pool)逻辑里,确认有没有拿到同一对象:

python 复制代码
if obj is cached_obj:
    ...

五、其他"类似"的关键字/运算符:到底判断什么?

这里列出几个经常和 is 搞混的,同时说明它们判断的到底是什么。

1. == / !=:值相等比较

  • 调用对象的 __eq__ / __ne__ 方法,判断"值"是否相等。
  • 对于内建类型,已经有合理实现;对于自定义类,可以自行重写。

示例:

python 复制代码
class User:
    def __init__(self, id, name):
        self.id = id
        self.name = name

u1 = User(1, "Alice")
u2 = User(1, "Alice")

print(u1 == u2)  # 默认情况 False ------ 因为 User 没有实现 __eq__
print(u1 is u2)  # False ------ 完全不同的对象

如果你希望"只要 id 一样就算同一个用户",可以:

python 复制代码
class User:
    def __init__(self, id, name):
        self.id = id
     self.name = name

    def __eq__(self, other):
        if isinstance(other, User):
            return self.id == other.id
        return NotImplemented

u1 = User(1, "Alice")
u2 = User(1, "Alice")

print(u1 == u2)  # True(值意义下相等)
print(u1 is u2)  # False(仍不是同一对象)

总结:== 是"值相等",is 是"同一对象"。


2. in / not in:成员测试

in 并不比较"地址"或"值相等",它是"在不在里面"。

对不同容器有不同语义:

  • 对列表/元组等序列:逐个元素用 == 比较
  • 对集合:基于散列,近似 O(1) 查找,用 == 判断同一个元素
  • 对字典:检查"键"是否存在
python 复制代码
lst = [1, 2, 3]
print(1 in lst)   # True(用 == 逐个比较)
print(4 in lst)   # False

s = {1, 2, 3}
print(1 in s)     # True

d = {"a": 1, "b": 2}
print("a" in d)   # True,检查键
print(1 in d)     # False

成员测试的本质:"是否存在等值元素" ,这里的相等是由 == 决定,不是 is


3. is vs ==in 中的潜在混淆

有时你会看到类似代码:

python 复制代码
None in seq

这背后是:

  • 逐个元素,用 ==None 比较

如果你想"列表里是否包含那个确切的对象实例 obj",而不是"包含一个值相同的对象",你可能需要:

python 复制代码
any(item is obj for item in seq)

4. isbool 上下文

记住一点:is 返回的是布尔值 True / False,常用于条件判断:

python 复制代码
if x is None:
    ...

而对象本身在布尔上下文中也会被转换成 True / False(通过 __bool____len__):

python 复制代码
if some_list:  # 空列表为 False,非空列表为 True
    ...

这与 is 完全是两码事,不要混淆"真假"和"是否为同一个对象"。


六、岔开一点:几个常被误会"比地址"的场景

1. 集合与字典中的"同一个元素"

python 复制代码
s = set()
a = [1, 2]
b = [1, 2]

s.add(a)
print(b in s)   # False ------ 虽然值相同,但列表不可哈希,代码本身会报错

对于可哈希对象(如 int、str、不可变 tuple):

python 复制代码
s = set()
a = (1, 2)
b = (1, 2)

s.add(a)
print(b in s)  # True ------ 基于 hash + ==,不是 is

set/dict 判断"是否存在",依据的是:

  1. hash(obj):散列值(快速定位)
  2. ==:真正的相等判断(排除散列冲突)

跟"地址"无关。


七、总结与实践建议

1. 记住这三句话

  1. is 判断是否为同一个对象(同一身份),不管值是否相同。
  2. == 判断值是否相等 ,由类型的 __eq__ 决定。
  3. 判断数值、字符串、容器内容是否相同,用 ==,不要用 is

2. 使用 is 的正确场景

  • 判断是否为 None
    • if x is None: / if x is not None:
  • 判断是否为某个明确的单例对象
    • 自己设计的 SENTINEL = object()
  • 判定两个变量是否指向同一个实例(如缓存、对象池)

3. 使用 == 的场景

  • 几乎所有"内容比较"的场景:
    • 数字是否相等
    • 字符串内容是否相同
    • 列表、字典等数据结构内容是否相同
    • 自定义类希望根据字段判断相等性时(记得重写 __eq__
相关推荐
天天进步20152 小时前
Python全栈项目:实时数据处理平台
开发语言·python
sheji34162 小时前
【开题答辩全过程】以 基于Python的餐饮统计系统的设计和实 现为例,包含答辩的问题和答案
开发语言·python
elseif1232 小时前
【C++】并查集&家谱树
开发语言·数据结构·c++·算法·图论
catchadmin2 小时前
2026 年 PHP 前后端分离后台管理系统推荐 企业级方案
开发语言·php
LGL6030A2 小时前
Java学习历程26——线程安全
java·开发语言·学习
遨游xyz2 小时前
排序-快速排序
开发语言·python·排序算法
iFeng的小屋2 小时前
【2026年新版】Python根据小红书关键词爬取所有笔记数据
笔记·爬虫·python
m0_561359672 小时前
使用Python处理计算机图形学(PIL/Pillow)
jvm·数据库·python
LeonDL1682 小时前
基于YOLO11深度学习的衣物识别系统【Python源码+Pyqt5界面+数据集+安装使用教程+训练代码】【附下载链接】
人工智能·python·pyqt5·yolo数据集·yolo11数据集·yolo11深度学习·衣物识别系统