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

为什么Python中is运算符对classmethod的比较结果与id判断不一致

该现象的底层技术原因

首先给出测试代码:

class s:
    a = 0
    
    def obj(self):
        pass
    
    @classmethod
    def cla(cls):
        pass
    
    @staticmethod
    def sta():
        pass
    
t = s()

print(t.a is s.a)
print(t.obj is s.obj)
print(t.cla is s.cla)
print(t.sta is s.sta)

print(id(t.a), id(s.a))
print(id(t.obj), id(s.obj))
print(id(t.cla), id(s.cla))
print(id(t.sta), id(s.sta))

print(id(t.a) == id(s.a))
print(id(t.obj) == id(s.obj))
print(id(t.cla) == id(s.cla))
print(id(t.sta) == id(s.sta))

核心原理分为三点:

1. 方法访问的描述符绑定逻辑

Python中@classmethod装饰的类方法、普通定义的实例方法,本质都是实现了描述符协议的对象。每次通过类或者实例访问这类方法时,描述符的__get__方法都会生成一个全新的绑定方法对象:

  • 访问t.cla时,会生成绑定到类s的类方法绑定实例
  • 访问s.cla时,同样会生成一个新的绑定到类s的类方法绑定实例
    二者是完全独立的对象,仅绑定的目标类相同。

2. 临时对象内存复用导致id相等的假象

id()返回的是对象存活周期内的唯一内存地址,对象被销毁后,它占用的内存地址可以被新创建的对象复用。
你分开打印id(t.cla)和id(s.cla)时,执行流程是:

  1. 计算t.cla生成绑定方法对象 → 读取内存地址 → 打印id → 该临时对象没有被任何变量引用,立刻被垃圾回收,内存释放
  2. 计算s.cla生成新的绑定方法对象 → 刚好复用了上一步刚释放的内存地址 → 打印出来的id值和上一步完全相同
    这个相等只是临时对象内存复用的巧合,两个对象从来没有同时存在过。

3. is运算符的判断逻辑

执行t.cla is s.cla时,解释器会先计算左右两边的表达式结果,也就是同时生成两个绑定方法对象,此时两个对象都处于存活状态,不会发生内存复用,内存地址自然不同,所以返回False。

你可以通过持有对象的方式验证该逻辑:

a = t.cla
b = s.cla
# 两个对象同时存活,id不会相等
print(id(a) == id(b)) # 返回False
print(a is b) # 返回False

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 12:57:02