- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
第27章 更多实例
特别是,在本章中,我们将编写两个类:
·Person——创建并处理关于人员的信息的一个类。
·Manager——一个定制的Person,修改了继承的行为。
在这个过程中,我们将创建两个类的实例并测试它们的功能。当我们完成之后,将给出使用类的一个漂亮的例子,我们把实例存储到一个shelve的面向对象数据库中,使它们持久化。通过这种方式,我们可以把这些代码用作模板,从而发展为完全用Python编写的一个完备的个人数据库。
除了实际的工具,我们在这里的目标还具有教育意义:本章提供了关于Python中面向对象程序设计的教程。通常,人们能够掌握上一章中书面上的类语法,但是,当面对必须从头编写一个新类的时候,要搞清楚如何下手还是有麻烦。出于这一目的,我们将在这里每次介绍一个步骤,帮助你学习基础知识;我们将逐渐地构建类,以便可以看到其功能如何组合到一个完整的程序中。
最后,我们的类在代码量上相对较小,但是它们将展示Python的OOP模型的所有主要思想。不管其语法细节如何,Python的类系统实际上很大程度上就是在一堆对象中查找属性,并为函数给定一个特殊的第一个参数。
步骤1:创建实例
好了,对于设计阶段介绍了这么多,让我们开始实现。第一个任务是开始编写主类Person。在你喜欢的文本编辑器中,打开一个新的文件以便编写代码。在Python中,模块名使用小写字母开头,而类名使用一个大写字母开头,这是通用的惯例;就好像方法中使用self作为参数名,这可能不是语言所要求的,但是,这种违背惯例的做法很可能让随后阅读你的代码的人搞混淆了。按照惯例,我们将新的模块文件命名为person.py,将其中的类命名为Person,如下所示:
在本章前面部分,我们所有的工作都在这个文件中完成。在Python中的单个模块文件中,我们可以编写任意多个函数和类,并且,如果我们稍后添加不太相关的内容,这个person.py的名字可能显得意义不大。现在,我们将假设其中的所有内容都是和Person相关的。正如我们所了解的,当模块拥有一个单一、一致的用途的时候,它们会工作得更好。
编写构造函数
现在,我们要做的有关Person类的第一件事情就是记录关于人员的基本信息,如果你愿意的话,就填充记录字段。当然,在Python的术语中,这叫做实例对象属性,并且它们通常通过给类方法函数中的self属性赋值来创建。赋给实例属性第一个值的通常方法是,在__init__构造函数方法中将它们赋给self,构造函数方法包含了每次创建一个实例的时候Python会自动运行的代码。让我们给自己的类添加一个构造函数:
这是很常见的编码模式:我们传入的数据作为构造函数方法的参数附加到一个实例上,并且将它们赋给self以保持持久。在OO术语中,self就是新创建的实例对象,而name、job和pay变成了状态信息,即保存在对象中供随后使用的描述性数据。尽管其他的技术(例如,封装作用域引用)也可以保存细节,但实例属性使得这个过程很明确而且易于理解。
注意,这里参数名出现了两次。这段代码乍看起来有点多余,但实际上不是这样。例如,job参数在__init__函数的作用域里是一个本地变量,但是self.job是实例的一个属性,它暗示了方法调用的内容。这是两个不同的变量,但恰好具有相同的名字。通过self.job=job把本地的job赋给了self.job属性,我们在实例中保存了传入的job以供随后使用。在Python中,通常一个名字赋给什么地方(或者说,它赋给了什么对象)决定了它的含义是什么。
说到参数,__init__实在没有什么奇妙之处,只不过当产生一个实例的时候,会自动调用它并且它有特殊的第一个参数。尽管它的名字很怪异,它仍然是一个常规的函数,并且支持我们已经介绍的所有的函数特性。例如,我们可以为它的参数提供默认值,从而当参数的值不可用的情况下,就不必提供参数值。
为了便于说明,我们让job参数成为可选的参数,它将默认为None,这意味着所创建的人(目前)没有工作。如果job默认为None,我们可能也希望默认的pay为0,以保持一致性(除非你知道有某些人能够做到不干工作光拿钱)。实际上,我们必须为pay指定一个默认值,因为根据Python的语法规则,一个函数定义中,在第一个拥有默认值的参数之后的任何参数,都必须拥有默认值:
这段代码意味着当我们创建Person的时候,需要给name传入值,但是job和pay现在是可选的;如果忽略这两个值的话,它们默认为None和0。通常,self参数由Python自动填充以引用实例对象,把值赋给self属性就会将值赋给新的实例。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论