- 译者序
- 前言
- 第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语句主体中的语句会建立其属性。当Python执行class语句时(不是调用类),会从头至尾执行其主体内的所有语句。在这个过程中,进行的赋值运算会在这个类作用域中创建变量名,从而成为对应的类对象内的属性。因此,类就像模块和函数:
·就像函数一样,class语句是本地作用域,由内嵌的赋值语句建立的变量名,就存在于这个本地作用域内。
·就像模块内的变量名,在class语句内赋值的变量名会变成类对象中的属性。
类的主要的不同之处在于其命名空间也是Python继承的基础。在类或实例对象中找不到的所引用的属性,就会从其他类中获取。
因为class是复合语句,所以任何种类的语句都可位于其主体内:print、=、if、def等。当class语句自身运行时(不是稍后调用类来创建实例的时候),class语句内的所有语句都会执行。在class语句内赋值的变量名,会创建类属性,而内嵌的def则会创建类方法,但是,其他赋值语句也可制作属性。
例如,把简单的非函数的对象赋值给类属性,就会产生数据属性,由所有实例共享。
在这里,因为变量名spam是在class语句的顶层进行赋值的,因此会附加在这个类中,从而为所有的实例共享。我们可通过类名称修改它,或者是通过实例或类引用它[1]。
这种类属性可以用于管理贯穿所有实例的信息。例如,所产生的实例的数目的计数器(我们会在第31章进一步扩展这个概念)。现在,如果我们通过实例而不是类来给变量名spam赋值时,看看会发生什么:
对实例的属性进行赋值运算会在该实例内创建或修改变量名,而不是在共享的类中。通常的情况下,继承搜索只会在属性引用时发生,而不是在赋值运算时发生:对对象属性进行赋值总是会修改该对象,除此之外没有其他的影响[2]。例如,y.spam会通过继承而在类中查找,但是,对x.spam进行赋值运算则会把该变量名附加在x本身上。
下面这个例子,可以更容易理解这种行为,把相同的变量名储存在两个位置。假设我们执行下列类。
这个类有两个def,把类属性与方法函数绑定在一起。此外,也包含一个=赋值语句。因为赋值语句是在类中赋值变量名data,该变量名会在这个类的作用域内存在,变成类对象的属性。就像所有类属性,这个data会被继承,从而被所有没有自己的data属性的类的实例所共享。
当创建这个类的实例的时候,变量名data会在构造函数方法内对self.data进行赋值运算,从而把data附加在这些实例上。
结果就是,data存在于两个地方:在实例对象内(由__init__中的self.data赋值运算所创建)以及在实例继承变量名的类中(由类中的data赋值运算所创建)。类的display方法打印了这两个版本,先以点号运算得到self实例的属性,然后才是类。
利用这些技术把属性储存在不同对象内,我们可以决定其可见范围。附加在类上时,变量名是共享的;附加在实例上时,变量名是属于每个实例的数据,而不是共享的行为或数据。虽然继承搜索会查找变量名,但总是可以通过直接读取所需要的对象,而获得树中任何地方的属性。
例如,在上一个例子中,明确了x.data或self.data,都会返回实例的名称(通常是隐藏在类中的相同名称);然而,MixedNames.data则是明确地找出类的名称。我们之后将会看到这种编程模式的各种角色。下一节会说明其中最常用的一种。
[1]如果你用过C++,大概会认出这与C++的静态数据成员的概念有些类似:也就是储存在类中的成员,与实例是不相关的。在Python中,这没有什么特别的:所有类属性都是在class语句中的赋值的变量名,无论它们是否恰巧引用的是函数(C++的方法)或其他事物(C++的成员)。
[2]除非该类用__setattr__运算符重载方法重新定义了属性的赋值运算去做其他的事(第29章将讨论这一内容)。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论