- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
类可以截获 Python 运算符
虽然我们可以把所有类行为实现为方法函数,运算符重载则让对象和Python的对象模型更紧密地结合起来。此外,因为运算符重载,让我们自己的对象行为就像内置对象那样,这可促进对象接口更为一致并更易于学习,而且可让类对象由预期的内置类型接口的代码处理。以下是重载运算符主要概念的概要。
·以双下划线命名的方法(__X__)是特殊钩子。Python运算符重载的实现是提供特殊命名的方法来拦截运算。Python语言替每种运算和特殊命名的方法之间,定义了固定不变的映射关系。
·当实例出现在内置运算时,这类方法会自动调用。例如,如果实例对象继承了__add__方法,当对象出现在+表达式内时,该方法就会调用。该方法的返回值会变成相应表达式的结果。
·类可覆盖多数内置类型运算。有几十种特殊运算符重载的方法的名称,几乎可截获并实现内置类型的所有运算。它不仅包括了表达式,而且像打印和对象建立这类基本运算也包括在内。
·运算符覆盖方法没有默认值,而且也不需要。如果类没有定义或继承运算符重载方法,就是说相应的运算在类实例中并不支持。例如,如果没有__add__,+表达式就会引发异常。
·运算符可让类与Python的对象模型相集成。重载类型运算时,以类实现的用户定义对象的行为就会像内置对象一样,因此,提供了一致性,以及与预期接口的兼容性。
运算符重载是可选的功能。主要是替其他Python程序员开发工具的人在使用它,而不是那些应用程序开发人员在使用。此外,不客气地讲,不要因为这看起来很“酷”就随便去试用。除非类需要模仿内置类型接口,不然应该使用更简单的命名方法。例如,员工数据库应用程序为什么要支持像*和+这类表达式呢?通常来说,像giveRaise和promote这类名称的方法更有意义。
因此,我们不会在本书中深入讨论Python每个可用的运算符重载方法。不过,有个运算符重载方法,你可能会在每个现实的Python类中遇见:__init__方法,也称为构造函数方法,它是用于初始化对象的状态的。你应该特别注意这个方法,因为__init__和self参数是了解Python的OOP程序代码的关键之一。
第三个例子
这是另一个例子。这一次,我们要定义Second Class的子类,实现三个特殊名称的属性,让Python自动进行调用:
·当新的实例构造时,会调用__init__(self是新的ThirdClass对象)[1]。
·当ThirdClass实例出现在+表达式中时,则会调用__add__。
·当打印一个对象的时候(从技术上讲,当通过str内置函数或者其Python内部的等价形式来将其转换为打印字符串的时候),运行__str__。
新的子类也定义了一个常规命名的方法,叫做mul,它在原处修改该实例的对象。如下是一个新的子类:
ThirdClass“是一个”SecondClass对象,所以其实例会继承SecondClass的display方法。但是,Third Class生成的调用现在会传递一个参数(例如,"abc"),这是传给__init__构造函数内的参数value的,并将其赋值给self.data。直接效果是,ThirdClass计划在构建时自动设置data属性,而不是在构建之后请求setdata调用。
此外,ThirdClass对象现在可以出现在+表达式和print调用中。对于+,Python把左侧的实例对象传给__add__中的self参数,而把右边的值传给other,如图26-3所示;__add__返回的内容成为+表达式的结果。对于print,Python把要打印的对象传递给__str__中的self;该方法返回的字符串看做是对象的打印字符串。使用__str__,我们可以用一个常规的print来显示该类的对象,而不是调用特殊的display方法。
图 26-3 在运算符重载中,在类的实例上执行的表达式运算符,和其他内置运算都会对应到类中特殊名称的方法。这些特殊方法是选用的,也可像平常那样继承。在这里,“+”表达式会触发"__add__"方法
__init__、__add__和__str__这样的特殊命名的方法会由子类和实例继承,就像这个类中赋值的其他变量名。如果方法没有在类中编写,Python会在其所有超类内寻找这类变量名。运算符重载方法的名称并不是内置变量或保留字,只是当对象出现在不同的环境时Python会去搜索的属性。Python通常会自动进行调用,但偶尔也能由程序代码调用(稍后会谈到这个问题。例如,__init__通常可手动调用来触发超类的构造函数)。
注意,__add__方法创建并返回这个类的新的实例对象(通过它的结果值调用ThirdClass)。但是,mul会在原处修改当前的实例对象(通过重新赋值self属性)。我们可以通过重载*表达式来实现后者,但是,这一点和内置类型的行为不同,就像数字和字符串,总是替*运算符创建新对象。通常的实践说明,重载的运算符应该以与内置的运算符实现同样的方式工作。因为运算符重载其实只是表达式对方法的分发机制,可以在自己的类对象中以任何喜欢的方式解释运算符。
[1]不要与模块色中的__init__.py文件相混淆!见第23章,以获取更详细的信息。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论