- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
OOP 是为了代码重用
那么,我们为什么对建立和搜索对象树感兴趣?虽然这得具备一些经验后才能了解的,但是妥善使用时,类所支持的代码重用的方式,是Python其他程序组件难以提供的。通过类,我们可以定制现有的软件来编写代码,而不是对现有代码进行在原处的修改,或者每个新项目都从头开始。
从基本的角度来说,类其实就是由函数和其他变量名所构成的包,很像模块。然而,我们从类得到的自动属性继承搜索,支持了软件的高层次的定制,而这是我们通过模块和函数做不到的。此外,类提供了自然的结构,让代码可以把逻辑和变量名区域化,这样也有助于程序的调试。
例如,因为方法只是有特殊第一参数的函数,我们可以把要处理的对象传给简单函数,来模拟其行为。不过,方法参与了类的继承,可让我们自然地通过新方法定义编写子类,通过这样定制现有的软件,而不需要对现有的代码进行在原处的修改。在模块及函数中是没有类似的概念的。
举个例子,假设任务是实现员工的数据库应用程序。作为一个Python OOP程序员,可能会先写个通用的超类,来定义组织中所有员工的默认的通用行为。
一旦你编写了这样的通用行为,就可以针对每个特定种类的员工进行定制,来体现各种不同类型和一般情况的差异。也就是说,可以编写子类,定制每个类型的员工中不同的行为。这个类型的员工的其他行为则会继承那个通用化的类。例如,如果工程师有独特的薪资计算规则(并非以小时计算),就可以在子类中只取代这一个方法。
因为这里的computeSalary版本在类树下面出现,所以会取代(覆盖)Employee中的通用版本。然后,你可以建立员工所属的员工类种类的实例,从而使其获得正确的行为:
注意我们可以对树中任何类创建实例,而不是只针对底端的类,创建的实例所用的类会决定其属性搜索从哪个层次开始。最后,这两个实例对象可能会嵌入到一个更大的容器对象中(例如,列表或另一个类的实例),利用本章开头所提到的组合概念,从而可以代表部门或公司。
当我们想查看这些员工的薪资时,可根据创建这个对象的类来计算,这也是基于继承搜索的原理[1]。
这是第4章和第16章介绍过的多态概念的又一实例。回想一下,多态是指运算的意义取决于运算对象。在这里,computeSalary方法在调用前,会通过继承搜索在每个对象中找到。在其他应用中,多态可用于隐藏(封装)接口差异性。例如,处理数据流的程序可以写成预期有输入和输出方法的对象,而不关心那些方法实际在做的是什么。
把针对各种数据来源所需读取和写入方法接口定制的子类的实例传入后,都可以重用这个processor函数,无论什么时候都可以让它来处理所需使用的任何数据来源:
此外,因为读取和写入方法的内部实现已分解至某个独立的位置,修改这些代码是不会与正在使用的代码产生冲突的。实际上,processor函数本身也可以是类,让转换器的转换逻辑通过继承添加,并让读取器和写入器能够通过组合方式嵌入(稍后会说明如何实现)。
一旦习惯了使用这种方式进行程序设计(通过软件定制),你就会发现,当要写新程序时,很多工作早已做好。你的任务大部分就是把已实现的程序所需行为的现有超类混合起来。例如,某人已写好了这个例子中的Employee、Reader和Writer类,用在完全不同的程序中。如果是这样,你就可以“毫不费力”地采用那个人的所有代码。
事实上,在很多应用领域中,你可以取得或购买超类集合体,也就是所谓的软件框架(framework),把常见程序设计任务实现成类,可以让你在应用程序中混合。这些软件框架可能提供一些数据库接口、测试协议、GUI工具箱等。利用软件框架,只需编写子类,填入所需的一两个方法。树中较高位置的框架类会替你做绝大多数的工作。在OOP中写程序,所需要做的就是通过编写自己的子类,结合和定制已调试的代码。
当然,需要花点时间学习如何充分利用这些类,从而实现这种OOP是理想化。实际应用中,面向对象工作也需要有实质性的设计工作,来全面实现类的代码重用的优点。结果,程序员开始将常见的OOP结构归类,称为设计模式(design pattern),来协助解决设计中的问题。不过,在Python中所编写的用于OOP的实际代码是如此的简单,在探索OOP时不会增加额外的障碍。想了解原因,请继续学习第26章。
[1]注意,这个例子中的company列表可以使用Python对象的pickle功能(我们在第9章学习文件时介绍过)储存在文件中,以产生永久保存的员工数据库。Python有一个名为shelve的模块,可以把类实例的pickle形式储存在以键读取的文件系统内。第三方开源ZODB系统也是做的相同的事,只不过它对商业级面向对象数据库有着更好的支持。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论