返回介绍

方法是对象:绑定或无绑定

发布于 2024-01-29 22:24:15 字数 3271 浏览 0 评论 0 收藏 0

方法(特别是绑定方法),通常简化了Python中的很多设计目标的实现。我们在第29章中学习__call__的时候简单地介绍了绑定方法。详细的介绍在这里给出,并且比你想象的还要通用和灵活。

在第19章中,我们学习了函数如何可以像常规对象一样处理。方法也是一种对象,并且可以用与其他对象大部分相同的方式来广泛地使用——可以对它们赋值、将其传递给函数、存储在数据结构中,等等。由于类方法可以从一个实例或一个类访问,它们实际上在Python中有两种形式。

无绑定类方法对象:无self

通过对类进行点号运算从而获取类的函数属性,会传回无绑定(unboud)方法对象。调用该方法时,必须明确提供实例对象作为第一个参数。在Python 3.0中,一个无绑定方法和一个简单的函数是相同的,可以通过类名来调用;在Python 2.6中,它是一种独特的类型,并且不提供一个实例就无法调用。

绑定实例方法对象:self+函数对

通过对实例进行全运算从而获取类的函数属性,会传回绑定(bound)方法对象。Python在绑定方法对象中自动把实例和函数打包,所以,不用传递实例去调用该方法。

这两种方法都是功能齐全的对象,可四处传递,就像字符串和数字。执行时,两者都需要它们在第一参数中的实例(也就是self的值)。这也就是为什么我们上一章在子类方法调用超类方法时,要刻意传入实例。从严格意义上来说,这类调用会产生无绑定的方法对象。

调用绑定方法对象时,Python会自动提供实例,来创建绑定方法对象的实例。也就是说,绑定方法对象通常都可和简单函数对象互换,而且对于原本就是针对函数而编写的接口而言,就相当有用了(参考后面的方框“为什么要在意:绑定方法和回调函数”部分中的例子)。

为了解释清楚,假设我们定义下面的类。

现在,在正常操作中,创建了一个实例,在单步中调用了它的方法,从而打印出传入的参数:

不过,其实,绑定方法对象是在过程中产生的,就在方法调用的括号前。事实上,我们可以获取绑定方法,而不用实际进行调用。object.name点号结合运算是一个对象表达式。在下列代码中,会传回绑定方法对象,把实例(object1)和方法函数(Spam.doit)打包起来。我们可以把这个绑定方法赋值给另一个变量名,然后像简单函数那样进行调用。

另一方面,如果对类进行点号运算来获得doit,就会得到无绑定方法对象,也就是函数对象的引用值。要调用这类方法时,必须传入实例作为最左侧参数。

扩展一下,如果我们引用的self的属性是引用类中的函数,那么相同规则也适用于类的方法。self.method表达式是绑定方法对象,因为self是实例对象。

大多数时候,通过点号运算取出方法后,就是立即调用,所以你不会注意到这个过程中产生的方法对象。但是,如果开始编写以通用方式调用对象的程序代码时,就得小心了,特别要注意无绑定方法:无绑定方法一般需要传入明确的实例对象[1]

在Python 3.0中,无绑定方法是函数

在Python 3.0中,该语言已经删除了无绑定方法的概念。我们在这里所介绍的无绑定方法,在Python 3.0中当作一个简单函数对待。对于大多数用途来说,这对你的代码没什么影响;任何一种方式,当通过一个实例来调用一个方法的时候,都会有一个实例传递给该方法的第一个参数。

显式类型测试程序可能受到影响,如果你打印出一个非实例的类方法,它在Python 2.6中显示“无绑定方法”(unbound method),在Python 3.0中显示“函数”(function)。

此外,在Python 3.0中,不使用一个实例而调用一个方法没有问题,只要这个方法不期待一个实例,并且你通过类调用它而不是通过一个实例调用它。也就是说,只有对通过实例调用,Python 3.0才会向方法传递一个实例。当通过一个类调用的时候,只有在方法期待一个实例的时候,才必须手动传递一个实例:

这里的最后一个测试在Python 2.6中失效,因为无绑定方法默认地需要传递一个实例;它在Python 3.0中有效,因为这样的方法当作一个简单函数对待,而不需要一个实例。尽管这会删除Python 3.0中某些潜在的错误陷阱(如果一个程序员偶然忘记传入一个实例,会怎么样呢?),但它允许类方法用作简单的函数,只要它们没有被传递并且不期望一个"self"实例参数。

如下的两个调用仍然在Python 3.0和Python 2.6中都失效,第一个(通过实例调用)自动把一个实例传递给一个并不期待实例的方法,而第二个(通过类调用)不会把一个实例传递给确实期待一个实例的方法:

由于这一修改,对于只通过类名而不通过一个实例调用的、没有一个self参数的方法,在Python 3.0中不再需要下一章介绍的staticmethod装饰器——这样的方法作为简单函数运行,不会接受一个实例参数。在Python 2.6中,这样的调用是错误的,除非手动地传递一个实例(下一章更详细地介绍静态方法)。

注意到在Python 3.0中的这一差别是很重要的,但是,从实用的角度来看,绑定方法通常更重要。因为,它们在一个单个的对象中把实例和函数配对起来,所以它们通常可以当做可调用对象对待。下一小节介绍了这样在代码中意味着什么。

注意:对于Python 3.0和Python 2.6中的无绑定方法处理的可视化说明,请参见本章稍后的多继承小节的lister.py示例。它的类打印出了从实例和类获取的方法的值,在Python的两个版本中分别这么做。

[1]参考第31章有关静态和类方法的讨论,以了解这个规则的例外。就像绑定方法一样,两者都可以冒充基本的函数,因为它们在调用时不需要实例。Python支持3种类方法——实例方法、静态方法和类方法,并且Python 3.0也允许类中的简单函数。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文