Python的is和==把我坑惨了,原来对象比较的水这么深

简介: 一篇用真实踩坑经历讲透Python中`is`与`==`区别的技术文:前者比内存地址(身份),后者比值内容。通过登录Bug、列表、小整数池、字符串驻留、自定义类等典型场景,厘清使用边界——**仅判断`None`/单例时用`is`,其余一律用`==`**。(239字)

一个让我熬夜到凌晨三点的Bug

先跟你说个真事儿。

上周五晚上,我写了一段用户登录的代码。逻辑很简单——从数据库查出用户信息,判断是不是管理员,决定跳转到哪个后台页面。

代码长这样:

user = get_user_from_db(user_id)  # 返回一个字典
if user['role'] is 'admin':
   redirect_to_admin_page()
else:
   redirect_to_user_page()

你猜怎么着?所有管理员登录后都跳转到了普通用户页面

我盯着屏幕看了半小时,数据库里role字段明明白白写着'admin',打印出来也是'admin',可if条件就是进不去。

后来把is换成==,一切正常了。

就这一个字符的区别,我熬到凌晨三点。

代理 IP 使用小技巧 让你的数据抓取效率翻倍 (68).png

从那以后我才真正搞明白,Python里is==根本不是一回事。今天我就把这次踩坑的教训好好跟你说说。

先记住一句话

在深入之前,先记住这句核心区别:

==比较的是值(内容),is比较的是身份(内存地址)。

用大白话讲:

  • ==问的是:这两个东西长得一不一样?
  • is问的是:这两个东西是不是同一个东西?

长得一样的东西,不一定是同一个东西。就像双胞胎长得一模一样,但他们是两个人。==看长相,is看身份证号。

Python里每个对象都有三个基本属性:id(身份标识)type(数据类型)value(值)is比的是id,==比的是value。

场景一:列表——最直观的对比

先看一段代码:

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

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

同样都是[1, 2, 3],为什么a is bTruea is c却是False

因为b = a这句,b只是给a取了个别名,a和b指向的是内存里同一个列表对象。

c = [1, 2, 3]新创建了一个列表。虽然内容和a一模一样,但它们是内存里两个不同的对象。

你可以用id()函数验证一下:

print(id(a))  # 比如 4364243328
print(id(b))  # 4364243328,和a一样
print(id(c))  # 4364202696,不一样

这就是为什么a is cFalse——它们的“身份证号”不同。

场景二:整数——那个把我骗得最惨的坑

整数比较是新手最容易翻车的地方。

看这个:

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

c = 257
d = 257
print(c is d)   # False

同样是两个相等的整数,256返回True,257返回False

这什么逻辑?

因为Python有个“小整数对象池”

Python启动的时候,会把-5256之间的整数提前创建好,放在一个池子里。以后你用这个范围内的任何数字,Python都直接从池子里拿,不会新建。

所以a = 256b = 256,两个变量拿到的其实是同一个整数对象。

但257不在池子里,每次赋值都会新创建一个对象。所以c is dFalse——值一样,但不是同一个东西。

这不就坑了吗? 我今天用is比较100没问题,明天换成1000就出bug了。这种不确定性,谁受得了?

场景三:字符串——时灵时不灵

字符串也有类似的坑。

s1 = "hello"
s2 = "hello"
print(s1 is s2)   # 通常是 True

但换个写法:

s1 = "hello world!"
s2 = "hello world!"
print(s1 is s2)   # 可能是 False

Python对字符串也有“驻留”机制——某些简单的字符串会被缓存复用。但规则很复杂,跟字符串长度、内容都有关系。

你永远不确定is会不会返回True。所以比较字符串值的时候,**永远用==**。

场景四:自定义类——又一个隐形陷阱

自己定义的类,==的行为也不一样。

class Person:
   def __init__(self, name):
       self.name = name

p1 = Person("张三")
p2 = Person("张三")

print(p1 == p2)   # False
print(p1 is p2)   # False

两个Person对象,名字一样,但==is都返回False

因为默认情况下,自定义类的==比较的也是内存地址,和is没有区别。

如果想让==比较内容,需要自己实现__eq__方法:

class Person:
   def __init__(self, name):
       self.name = name
   
   def __eq__(self, other):
       return self.name == other.name

p1 = Person("张三")
p2 = Person("张三")
print(p1 == p2)   # True
print(p1 is p2)   # False

到底什么时候用is

说了这么多坑,那is是不是就没用了?

当然不是。**is有它专属的使用场景**:

1. 判断None

这是Python官方推荐的做法:

# ✅ 正确
if data is None:
   print("数据为空")

# ❌ 不推荐
if data == None:
   print("数据为空")

因为None在Python里是单例——整个程序里只有一个None对象。用is判断既准确又高效。

2. 判断单例

类似的,TrueFalse也是单例,也可以用is

3. 检查两个变量是否指向同一个对象

比如你想确认两个变量是不是引用了同一个列表/字典实例。

除了这些情况,**比较值请一律用==**。

为什么is==快?

顺便说个冷知识:is==快。

因为is只是比较两个内存地址是否相同,就是一个整数比较。而==要调用对象的__eq__()方法,可能涉及复杂的值比较逻辑。

而且is不能被重载,行为是固定的。==可以被重载,不同类的==行为可能不一样。

别为了这点性能就用is比较值——正确性永远比性能重要。

总结一下

运算符 比较什么 通俗理解 使用场景
== 值是否相等 长得像不像 绝大多数情况
is 是否是同一个对象 是不是同一个人 判断None、单例、对象身份

记住这几个原则:

  1. **比较值,永远用==**——不管是数字、字符串、列表还是字典
  2. **判断None,用is**——这是Python社区的共识
  3. 别拿is比较整数和字符串——小整数池和字符串驻留会让结果时灵时不灵
  4. **自定义类要实现__eq__**——不然==is没区别

那次熬夜之后,我给自己定了个规矩:**除了判断None,一律用==**。

如果你现在代码里还在用is比较字符串或者大整数,赶紧去改了吧。别等到凌晨三点才发现问题。

目录
相关文章
|
1月前
|
存储 人工智能 弹性计算
有赞携手阿里云 FC 云沙箱,构建企业级 AI Agent 平台新范式
有赞为解决AI Agent分散建设、安全隔离难、成本高等问题,于2026年初启动企业级Agent SaaS平台“Agent Build”建设,选用阿里云FC云沙箱作为底层运行时,实现六维安全隔离、毫秒级弹性伸缩、存量Dify Workflow平滑迁移,显著提升研发效率并降低计算成本。
281 1
有赞携手阿里云 FC 云沙箱,构建企业级 AI Agent 平台新范式
|
2月前
|
数据采集 人工智能 自然语言处理
自动化比价系统:从采集到数据清洗,全链路打通教程
本文详解淘宝/京东/拼多多三平台自动化比价系统全链路:用OpenClaw自然语言采集、站大爷隧道代理防封(24小时成功率98.2%+)、AI智能清洗价格(统一格式、核销优惠、去重校验),自动生成可决策的比价报告与飞书预警,真正实现“采得稳、洗得准、用得上”。
279 1
|
2月前
|
存储 API 数据库
RAG检索增强怎么搭建:从原理到落地的完整路径
RAG(检索增强生成)通过“先检索、再生成”机制,将外部知识库与大模型结合,解决幻觉、数据过时及私有数据不可用问题。涵盖文档解析、文本分块、向量化存储、检索生成四大环节,强调分块策略、检索质量与提示词约束的协同优化。(239字)
|
1月前
|
人工智能 安全 UED
刚刚,阿里悄悄上线了他们最新视频模型:Wan3.0【附10种神仙玩法】
1080P 30秒视频!打骨折价,AI视频终于卷起来啦~
333 0
|
3月前
|
Shell iOS开发 MacOS
npm全局安装后提示codex command not found的7种解决方法(2026)
2026 年呼声最高的 Claude Code 功能,悄悄在 v2.1.169 上线了,多数人还不知道它切目录时能把提示缓存保住,不是清掉重来。 如果你以前每次想去 git worktree 或者隔壁仓库工作,都得退出 Claude Code 重启——这套仪式从 2026-06-08 起可以扔掉了。新出的 /cd 命令让会话中途切到任何目录,前缀缓存还能活着。对 Claude Opus 4.8(输入 5 美元/M token、缓存读 0.5 美元/M token)来说,这意味着原本要重发的那一堆上下文打了一折。 但”保住缓存”这句话带 3 个星号。这篇把可验证的机制、操作步骤、3 个会让缓
|
3月前
|
弹性计算 运维 关系型数据库
阿里云CLI与批处理集成:云运维提效的5个实战技巧
在阿里云环境中,运维工程师每天面对大量重复性操作——批量ECS巡检、OSS文件同步、RDS备份管理、安全组规则维护等任务占用大量时间。本文分享5个基于阿里云CLI和批处理集成的实战技巧,通过aliyun-cli命令行工具、ossutil对象存储工具、RAM权限管理和自动化脚本框架,将云运维效率提升70%以上。以每月100台ECS实例的运维规模计算,年节省运维成本超过10万元。
|
3月前
|
数据采集 Web App开发 JavaScript
房源信息采集:链家/贝壳等房产网站的反爬策略应对方案
本文详解链家/贝壳房产数据采集的反爬困境与实战方案:针对IP封禁、滑块验证、JS动态渲染及“幽灵房”假数据等难题,提出OpenClaw驱动真实浏览器+站大爷高匿隧道代理+请求频率与指纹伪装三重防护策略,兼顾稳定性与合规性。(239字)
558 0
|
3月前
|
存储 人工智能 NoSQL
知识库构建:将采集到的数据存入向量数据库,打造企业私域知识库
本文手把手教你用OpenClaw构建企业AI知识库:解决PDF难检索、AI不懂业务、数据用完即弃等痛点。详解Builtin(开箱即用)、LanceDB(永久记忆)和阿里云Tablestore/Hologres(团队协作)三套向量数据库方案,含配置模板、命令及避坑指南,全程本地化、数据私有。(239字)
352 0
|
3月前
|
运维 算法 前端开发
用办公Agent实现智能工单:从客服请求到指派工程师的端到端自动化
本文介绍如何用办公Agent实现智能工单端到端自动化:从用户提问→自动创建/分类→智能派单→通知工程师→闭环反馈,将平均响应时间从47分钟压缩至90秒。详解5步流程、规则+LLM双分类、实时负载+技能匹配派单等核心设计,并分享避坑指南与落地路径。(239字)
573 0

热门文章

最新文章