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

Python中从类与对象访问函数为何内存地址不同?

关于Python方法绑定与内存地址的疑问

我在阅读Python描述符相关文档时遇到了如下示例代码:

>>> class D(object):
...     def f(self, x):
...         return x
>>> d = D()
>>> D.__dict__['f']  # Stored internally as a function
<function f at 0x00C45070>
>>> id(D.__dict__['f'])  # Memory location
49294384
>>> D.f  # Get from a class becomes an unbound method
<unbound method D.f>
>>> id(D.f )
48549440
>>> d.f  # Get from an instance becomes a bound method
<bound method D.f of <__main__.D object at 0x00B18C90>>
>>> id(d.f)
48549440

我理解Python会将类的函数定义作为独立对象存储在类的__dict__变量中,直接通过__dict__访问时其内存地址为49294384。但为何通过类(D.f)或对象(d.f)访问时,显示的是内存地址为48549440的不同方法对象?按道理不是应该指向__dict__中的同一个对象吗?请问原因是什么?


问题解答

这其实是Python中描述符协议在背后默默工作的结果,咱们一步步拆解来看:

  • 首先,Python里用def定义的函数其实都实现了描述符协议,它们自带__get__方法。当你通过类或者实例去访问这个函数的时候,Python会自动调用这个__get__方法,而不是直接返回__dict__里的原始函数对象。
  • 当你用D.__dict__['f']直接访问时,相当于绕开了描述符的逻辑,拿到的是存储在类命名空间里的原始函数本身,所以它的内存地址是49294384。
  • 当你访问D.f时,Python会调用函数的__get__方法,并且传入instance=None和owner=D,这时候__get__会返回一个**未绑定方法(unbound method)**对象——这个对象是个全新的包装器,它持有对原始函数和类的引用,但本身是独立的新对象,所以内存地址和原始函数不一样。
  • 当你访问d.f时,同样会触发__get__方法,不过这次传入的参数是instance=d和owner=D,返回的是**绑定方法(bound method)**对象——这个包装器会把实例d绑定到函数的第一个参数self上,它也是一个新的对象。
  • 至于你看到D.f和d.f的内存地址相同,这其实是个小巧合:在这个特定的解释器会话里,前一个未绑定方法对象被回收后,它占用的内存刚好被新创建的绑定方法对象复用了,本质上它们是完全不同的方法对象。

简单总结一下:方法对象(不管绑定还是未绑定)都是原始函数的"包装器",每次通过类或实例访问函数时,都会触发描述符的__get__逻辑来创建这个包装器,所以它们的内存地址自然和原始函数不一样。


内容的提问来源于stack exchange,提问作者Shiva Krishna Bavandla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:53:16