You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中对象ID、哈希值与类实例标识的区别及用途答疑

Python 三类对象标识的设计逻辑与适用场景

很多初学者刚接触自定义类的时候,都会把打印实例带出的地址、id()返回值、hash()返回值混为一谈,实际上三者从设计目标到适用场景完全没有重叠,是服务于不同语言机制的独立设计。

先看复现用的测试代码:

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

p1 = Person("Allen")
print(p1)
print(id(p1))
print(hash(p1))

典型CPython环境下的输出如下:

<__main__.Person object at 0x000001AE10CC7FD0>
1847117774800
115444860925

1. 打印实例时输出的地址串

这个值根本不是独立设计的标识,只是默认对象字符串表示方法的拼接内容:

  • 如果你写的自定义类没有重写__repr__方法,Python会调用基类object的默认__repr__实现,自动拼接出<模块名.类名 object at 十六进制数值>格式的字符串,主要作用是调试时给开发者快速肉眼区分不同实例。
  • 这个字符串里的十六进制数值,在官方CPython解释器里刚好是对象在C层面的内存首地址,你可以自行换算:例子里的id返回值1847117774800转成十六进制就是0x1AE10CC7FD0,和打印串里的地址完全一致。但这只是CPython的实现细节,不是通用规范——你完全可以重写__repr__返回任意内容,哪怕不带任何地址信息也不会影响代码运行,Python解释器本身不会拿这个打印串里的数值做任何逻辑判断。
  • 适用场景:仅用于调试打印、日志输出时给人看,没有任何程序逻辑层面的约束力。

2. id() 函数返回的对象ID

这是Python语言规范明确定义的对象唯一身份标识,有强制的规则约束:

  • 规则非常明确:一个对象从创建到被回收的整个生命周期内,id()返回值固定不变;同一时刻内存中存活的两个不同对象,id()返回值绝对不重复。
  • 适用场景:所有需要判断两个变量是否指向同一个内存对象的场景,我们常用的a is b身份判断,本质就是Python在底层判断id(a) == id(b)。
  • 注意:CPython里用内存地址当id值只是实现选择,不是所有Python解释器都这么做(比如PyPy的id实现就和内存地址无关),写代码时不要依赖"id等于内存地址"这个特性。

3. hash() 函数返回的哈希值

这是专门为哈希表结构设计的数值,服务于字典、集合这类基于哈希实现的容器:

  • 它的核心规则只有一条:如果两个对象用==判断相等,那它们的hash()返回值必须相等,否则字典、集合就无法正常找到存入的键。除此之外没有其他强制要求:不同对象可以有相同的哈希值(也就是哈希碰撞,哈希表自带碰撞处理逻辑);同一个对象在不同进程、不同Python版本下的哈希值可以不一样(比如Python默认开启字符串哈希随机化,每次启动进程字符串的哈希值都会变化,用来防止哈希碰撞攻击)。
  • 例子里的自定义类没有重写__eq__和__hash__方法,默认继承的object的哈希实现是基于对象id做数值变换得到的,所以哈希值和id值不相等,这是正常现象。如果是重写了__eq__的不可变对象,哈希值会基于对象的内容计算,和id完全无关——比如两个内容一样的字符串,哪怕是不同的对象(id不同),哈希值也会相等。
  • 适用场景:仅用于哈希表的存取位置计算、哈希类算法实现,绝对不能拿哈希值当对象的唯一标识用。

设计逻辑总结

三者完全是为不同需求设计的,不存在功能重叠:

  • 打印带出的地址是给开发者看的调试文本,无逻辑约束力
  • id()返回值是给解释器判断对象身份用的,保证对象生命周期内全局唯一
  • hash()返回值是给哈希容器做索引计算用的,只要求相等对象哈希一致,不要求全局唯一

内容的提问来源于stack exchange,提问作者Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:27:16