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

Python中类方法与实例方法的id差异及绑定机制疑问

Python中类方法与实例绑定方法的id差异解析

核心疑问

示例代码中,id(p.name_as_upper)与id(p2.name_as_upper)结果相同,但和id(Person.name_as_upper)结果不同;同时修改Person.name_as_upper后,实例p调用该方法的结果也随之变化。需要澄清类方法与实例关联方法的底层逻辑。

示例代码

class Person:
    def __init__(self, name: str) -> None:
        self.name = name

    def name_as_upper(self) -> str:
        return self.name.upper()

p = Person("john")
p2 = Person("sarah")
print(
    id(p.name_as_upper), id(p2.name_as_upper), id(Person.name_as_upper)
)  # first two are the same, last one different

print(p.name_as_upper())  # JOHN
print(Person.name_as_upper(p))  # JOHN

Person.name_as_upper = (
    lambda self: self.name.upper() + " - suffix"
)  # "point" name_as_upper method object to different method

print(p.name_as_upper())  # JOHN - suffix
print(Person.name_as_upper(p))  # JOHN - suffix

原理澄清

1. 类函数与实例绑定方法的本质区别

  • Person.name_as_upper是类中定义的原始函数对象,它独立于任何实例,属于类的属性。
  • 当你访问p.name_as_upper或p2.name_as_upper时,Python会动态生成一个绑定方法(bound method)对象——这个对象把实例(比如p)和类的函数(Person.name_as_upper)绑定在一起,调用时会自动把实例作为第一个参数传入函数。

2. 实例绑定方法的id为何看似相同

示例中id(p.name_as_upper)和id(p2.name_as_upper)相同,是因为Python的内存回收机制:当你获取第一个绑定方法后,它没有被引用,很快被销毁;获取第二个绑定方法时,复用了之前释放的内存地址,所以id值巧合一致。实际上,每次访问实例的方法属性,都会生成一个新的绑定方法对象。

3. 修改类方法后实例方法随之变化的原因

实例本身并不会存储方法的副本,当你访问p.name_as_upper时,Python会优先从实例自身的属性中查找,找不到就去类的属性里找对应的函数,再动态生成绑定方法。因此,当你修改Person.name_as_upper指向新的函数后,下次访问实例的该方法时,会用新函数生成绑定方法,调用结果自然随之改变。

4. 调用等价性的本质

p.name_as_upper()等价于Person.name_as_upper(p),是因为绑定方法在调用时,会自动将绑定的实例作为第一个参数传递给类的函数,这和手动把实例传给类函数的效果完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 08:53:13