- 译者序
- 前言
- 第1章 问答环节
- 第2章 Python 如何运行程序
- 第3章 如何运行程序
- 第4章 介绍 Python 对象类型
- 第5章 数字
- 第6章 动态类型简介
- 第7章 字符串
- 第8章 列表与字典
- 第9章 元组、文件及其他
- 第10章 Python 语句简介
- 第11章 赋值、表达式和打印
- 第12章 if 测试和语法规则
- 第13章 while 和 for 循环
- 第14章 迭代器和解析,第一部分
- 第15章 文档
- 第16章 函数基础
- 第17章 作用域
- 第18章 参数
- 第19章 函数的高级话题
- 第20章 迭代和解析,第二部分
- 第21章 模块:宏伟蓝图
- 第22章 模块代码编写基础
- 第23章 模块包
- 第24章 高级模块话题
- 第25章 OOP:宏伟蓝图
- 第27章 更多实例
- 第28章 类代码编写细节
- 第29章 运算符重载
- 第30章 类的设计
- 第31章 类的高级主题
- 第32章 异常基础
- 第34章 异常对象
- 第35章 异常的设计
- 第36章 Unicode 和字节字符串
- 字符串基础知识
- Python 的字符串类型
- 文本和二进制文件
- Python 3.0 中的字符串应用
- 转换
- 编码 Unicode 字符串
- 编码非ASCII文本
- 编码和解码非ASCII文本
- 其他 Unicode 编码技术
- 转换编码
- 在 Python 2.6 中编码 Unicode 字符串
- 源文件字符集编码声明
- 使用 Python 3.0 Bytes 对象
- 序列操作
- 创建 bytes 对象的其他方式
- 混合字符串类型
- 使用 Python 3.0(和 Python 2.6)bytearray 对象
- 使用文本文件和二进制文件
- Python 3.0 中的文本和二进制模式
- 类型和内容错误匹配
- 使用 Unicode 文件
- 在 Python 3.0 中处理 BOM
- Python 2.6 中的 Unicode 文件
- Python 3.0 中其他字符串工具的变化
- Struct二进制数据模块
- pickle对象序列化模块
- XML解析工具
- 本章小结
- 本章习题
- 习题解答
- 第37章 管理属性
- 第38章 装饰器
- 第39章 元类
- 附录A 安装和配置
- 附录B 各部分练习题的解答
- 作者介绍
- 封面介绍
方法是对象:绑定或无绑定
在第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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论