Python3中类实例是否共享类方法?id与is结果矛盾解惑
这是个非常棒的问题,刚好戳中了Python方法绑定的核心细节,咱们一步步拆解清楚:
一、a.something 和 b.something 的内存地址疑惑
首先要明确:当你通过实例访问类定义的方法时,Python会动态创建一个绑定方法对象(bound method),这个对象会把实例和类中的原始函数绑定在一起。
那为什么你测试时id(a.something)和id(b.something)的数值相同?这是Python内存复用的小把戏:
- 当你调用
id(a.something)时,临时创建的绑定方法对象在获取完id后就没有被引用了,会被垃圾回收机制释放内存; - 紧接着调用
id(b.something)时,新创建的绑定方法对象刚好复用了之前释放的那块内存地址,所以id数值一致。
但这两个绑定方法本质上是完全不同的对象,你换一种方式测试就能看出来:
# 先把两个绑定方法存起来,避免被立即回收 meth_a = a.something meth_b = b.something print(meth_a is meth_b) # 输出 False,说明是不同对象 print(id(meth_a), id(meth_b)) # 这里的id可能不同,也可能相同,全看内存分配情况
你之前写的id(a.something) is id(b.something)其实是个“伪测试”——因为两次id调用中间,第一个绑定方法已经被销毁了,比较的是两个不同对象的id数值,而非对象本身。
二、a.something() 的调用解析机制
当你尝试调用a.something()时,Python的属性查找和方法绑定流程是这样的:
- 先在实例
a的__dict__(实例自身的属性字典)里找something——显然找不到,因为我们没给a单独绑定这个属性; - 接着去
a的类MyClass的__dict__里查找,找到了类定义的something函数; - Python自动把这个函数包装成绑定方法对象,把实例
a作为第一个参数(也就是我们常写的self)预绑定进去; - 最后调用这个绑定方法时,它会自动调用类中的原始
something函数,并把a传递进去。
⚠️ 注意哦:你当前的something定义没有self参数,所以直接调用a.something()会报错——Python会强行传入实例a作为第一个参数,但函数不接受任何参数。正确的类方法定义应该是:
class MyClass: def something(self): pass
另外要强调:类中的MyClass.something是唯一的函数对象,所有实例的绑定方法都是基于这个原始函数创建的,只是绑定的实例不同而已。
三、为什么实例的属性列表里会有something
当你用dir(a)查看实例的可用属性时,dir()函数的逻辑是:遍历实例自身的属性,再遍历类及所有父类的属性,最后整理成有序列表。所以类中定义的something方法会被包含进来,因为它是可以通过实例a访问到的属性。
内容的提问来源于stack exchange,提问作者user9760743
相关产品推荐
相关产品推荐

