Python类中绑定方法与非绑定方法的原理与区别

Jasper
Jasper
发布时间:2026-10-14 | 2人浏览过
原创

本文详细解析Python中类方法的两种调用形式:绑定方法与非绑定方法。通过代码示例说明实例调用自动传递self形成绑定方法,而类调用需显式传入实例否则报错。结合__get__描述器协议,揭示两者本质差异,帮助开发者深入理解Python面向对象机制。

引言:类方法的调用方式

写在之前

在Python的类定义中,除了属性外,还包含方法、文档字符串及注释等内容。其中,文档和注释主要供人类阅读,计算机在执行时并不关注它们。此前我们提到,通常通过实例来调用方法,但这并非唯一方式。本文将重点探讨另一种调用方式,即「绑定方法」与「非绑定方法」的概念及其区别。

绑定方法与非绑定方法详解

绑定方法和非绑定方法

在Python中,除了特殊方法(如魔术方法)外,类中的普通方法也是日常开发中频繁使用的组件。为了深入理解其机制,下面通过具体示例进行分析:


>>> class Sample:
...  def f(self):
...    print('f function is a normal method')
...
>>> sam = Sample()
>>> sam.f
f function is a normal method

根据之前的学习可知,在类Sample中定义的方法f(),本质上是一个函数,其首要参数必须是self。为了区分普通函数,我们在类内部将其命名为「方法」。但从本质上看,它与普通函数并无二致。

当创建实例后,通过实例调用该方法时,Python解释器会自动将实例作为第一个参数隐式传递给该方法。因此,在调用时无需显式写出self参数。这一知识点已多次强调,旨在帮助读者明确理解self即代表实例本身。

若希望显式地将实例传递给方法,可采用以下方式:


>>> Sample.f(sam)
f function is a normal method

上述方式能更好地验证前述观点,即实例化后,self与实例sam指向同一对象。通常情况下,在类内部使用self,而在类外部使用具体实例名(如sam),二者各司其职。

那么,如果直接使用类来调用方法且不传递实例,会发生什么情况呢?


>>> Sample.f()
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unbound method f() must be called with Sample instance as first argument (got nothing instead)

结果会报错。仔细分析错误信息可知,这是因为缺少了一个必需的参数——实例。因此,必须显式传入一个实例才能正确调用。

在Python中,一切皆对象。因此,类Sample的方法f()本身也是一个对象,具体而言是一个函数对象。我们可以通过以下方式获取该对象:


>>> Sample.f
<function Sample.f at 0x000000000244AB48>

同样,我们也可以通过实例来获取该方法对象:


>>> sam.f
<bound method Sample.f of <__main__.sample instance at 0x000000000244AB48>>

通过实例获取该方法对象时,我们观察到其类型为「绑定方法」(bound method)。

接下来,我们将逐步深入探讨「绑定方法」与「非绑定方法」的本质概念。

在类Sample的属性中,存在一个名为__dict__的属性方法。我们在前文曾介绍过它,此处将利用它来查看类的内部信息:


>>> sample.__dict__['f']
<function f at 0x000000000250D828>

从上述输出可以看出,f确实是一个函数对象。

描述器协议与本质分析

接下来引入一个新概念:「描述器」。什么是描述器?在Python中,若对象包含__get__()、__set__()和__delete__()这几个特殊方法之一,则该对象被称为「描述器」。

描述器在Python中使用广泛。例如,前文提到的super关键字,其背后实现机制涉及属性、实例方法及继承等场景,均依赖于描述器。关于描述器的详细内容,此处不再赘述,提及它的目的仅在于解决绑定方法与非绑定方法的问题。有兴趣的读者可自行查阅相关资料。

在此,我们仅关注__get__()方法,其所谓的描述器协议如下:


des.__get__(self,obj,type=None) ---> value

将上述协议应用到前面的示例中,操作如下:


>>> sample.__dict__['f'].__get__(sam,sample)
<bound method sample.f of <__main__.sample instance at 0x000000000244AB48>>

可以发现,上述显示的结果与sam.f的输出一致。综上所述,我们可以得出以下结论:当通过类获取方法时,得到的是非绑定方法对象;而当通过实例获取方法时,得到的是绑定方法对象。

总结与展望

写在之后

关于绑定方法和非绑定方法的讨论至此结束。类的方法种类繁多,除上述两种外,还包括静态方法和类方法等,我将在后续文章中逐一介绍,敬请期待。

写出来的东西是我的,看进去的东西才是你的。希望你不要浪费时间,确保学有所得。如果文章对你有帮助,欢迎点赞和转发,感谢支持。

The end。

以上就是详解python方法之绑定方法与非绑定方法的详细内容,更多关于python 绑定方法与非绑定方法的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表