- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
编写类树
·每个class语句会生成一个新的类对象。
·每次类调用时,就会生成一个新的实例对象。
·实例自动连接至创建了这些实例的类。
·类连接至其超类的方式是,将超类列在类头部的括号内。其从左至右的顺序会决定树中的次序。
例如,要建立图25-1的树,我们可以运行这种形式的Python代码(在这里省略了class语句中的内容)。
在这里,通过运行三个class语句创建了三个类对象,然后通过两次调用类C1,创建两个实例对象,这就好像它是一个函数一样。这些实例记住了它们来自哪个类,而类C1也记住了它所列出的超类。
从技术角度来讲,这个例子使用的是所谓的多重继承。也就是说,在类树中,类有一个以上的超类。在Python中,如果class语句中的小括号内有一个以上的超类(像这里的C1),它们由左至右的次序会决定超类搜索的顺序。
因为继承搜索以这种方式进行,你要进行属性附加的对象就变得重要起来:这决定了变量名的作用域。附加在实例上的属性只属于那些实例,但附加在类上的属性则由所有子类及其实例共享。稍后,我们将会深入研究把属性增加在这些对象上的代码。我们将会发现:
·属性通常是在class语句中通过赋值语句添加在类中,而不是嵌入在函数的def语句内。
·属性通常是在类内,对传给函数的特殊参数(也就是self),做赋值运算而添加在实例中的。
例如,类通过函数(在class语句内由def语句编写而成)为实例提供行为。因为这类嵌套的def会在类中对变量名进行赋值,实际效果就是把属性添加在了类对象之中,从而可以由所有实例和子类继承。
在这样的环境下,def的语法没有什么特别之处。从操作的角度来看,当def出现在这种类的内部时,通常称为方法,而且会自动接收第一个特殊参数(通常称为self),这个参数提供了被处理的实例的参照值[1]。
因为类是多个实例的工厂,每当需要取出或设定正由某个方法调用所处理的特定的实例的属性时,那些方法通常都会通过这个自动传入的参数self。在之前的代码中,self是用来储存两个实例之一的内部变量名的。
就像简单变量一样,类和实例属性并没有事先声明,而是在首次赋值时它的值才会存在。当方法对self属性进行赋值时,会创建或修改类树底端实例(也就是其中一个矩形)内的属性,因为self自动引用正在处理的实例。
事实上,因为类树中所有对象都不过是命名空间对象,我们可以通过恰当的变量名读取或设置其任何属性。只要变量名C1和I1都位于代码的作用域内,写C1.setname和写I1.setname同样都是有效的。
就目前编写的代码而言,直到setname方法调用前,C1类都不会把name属性附加在实例之上。事实上,调用I1.setname前引用I1.name会产生未定义变量名的错误。如果类想确保像name这样的变量名一定会在其实例中设置,通常都会在构造时填好这个属性。
写好并继承后,每次从类产生实例时,Python会自动调用名为__init__的方法。新实例会如往常那样传入__init__的self参数,而列在类调用小括号内的任何值会成为第二以及其后的参数。其效果就是在创建实例时初始化了这个实例,而不需要额外的方法调用。
由于__init__方法的运行时机,它也称作是构造函数。这是所谓的运算符重载方法这种较大类型方法中最常用的代表,我们会在接下来几章详细介绍这种方法。这种方法会像往常一样在类树中被继承,而且在变量名开头和结尾都有两个下划线以使其变得特别。当能够支持通信操作的实例出现在对应的运算时,Python就会自动运行它们,而且它们是使用简单方法调用最常用的替代方法。这类方法也是可选的:省略时,不支持这类运算。
例如,要实现集合交集,类可能会提供名为intersect的方法,或者重载表达式运算符&,也就是编写名为__and__的方法来处理所需要的逻辑。因为运算符机制让实例的用法和外观类似于内置类型,可以让有些类提供一致而自然的接口,从而可以与预期的内置类型的代码兼容。
[1]如果你使用过C++或Java,就知道Python的self相当于this,但是Python中的self一定是明确写出的,这样使属性的读取更为明显。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论