- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
新式类的扩展
slots实例
将字符串属性名称顺序赋值给特殊的__slots__类属性,新式类就有可能既限制类的实例将有的合法属性集,又能够优化内存和速度性能。
这个特殊属性一般是在class语句顶层内将字符串名称顺序赋值给变量__slots__而设置:只有__slots__列表内的这些变量名可赋值为实例属性。然而,就像Python中的所有变量名,实例属性名必须在引用前赋值,即使是列在__slots__中也是这样。以下是说明的例子。
Slot对于Python的动态特性来说是一种违背,而动态特性要求任何名称都可以通过赋值来创建。这个功能看作是捕捉“打字错误”的方式(对于不在__slots__内的非法属性名做赋值运算,就会侦测出来),而且也是最优化机制。如果创建了很多实例并且只有几个属性是必需的话,那么为每个实例对象分配一个命名空间字典可能在内存方面代价过于昂贵。要节省空间和执行速度(程度对每个程序而言有所不同),slot属性可以顺序存储以供快速查找,而不是为每个实例分配一个字典。
Slot和通用代码
实际上,有些带有slots的实例也许根本没有__dict__属性字典,使得有些书中所写的元程序过于复杂(包括本书中的一些代码)。工具根据字符串名称通用地列出属性或访问属性,例如,必须小心使用比__dict__更为存储中立的工具,例如getattr、setattr和dir内置函数,它们根据__dict__或__slots__存储应用于属性。在某些情况下,两种属性源代码都需要查询以确保完整性。
例如,使用slots的时候,实例通常没有一个属性字典——Python使用第37章介绍的类描述符功能来为实例中的slot属性分配空间。只有slot列表中的名称可以分配给实例,但是,基于slot的属性仍然可以使用通用工具通过名称来访问或设置。在Python 3.0中(以及在Python 2.6中派生自object的类中):
没有一个属性命名空间字典,不可能给不是slots列表中名称的实例来分配新的名称:
然而,通过在__slots__中包含__dict__仍然可以容纳额外的属性,从而考虑到一个属性空间字典的需求。在这个例子中,两种存储机制都用到了,但是,getattr这样的通用工具允许我们将它们当做单独一组属性对待:
然而,想要通用地列出所有实例属性的代码,可能仍然需要考虑两种存储形式,因为dir也返回继承的属性(这依赖于字典迭代器来收集键):
由于两种都可能忽略,更正确的编码方式如下所示(getattr考虑到默认情况):
超类中的多个__slot__列表
然而,注意,这段代码只是解决了由一个实例继承的最低__slots__属性中的slot名称。如果类树中的多个类都有自己的__slots__属性,通用的程序必须针对列出的属性开发其他的策略(例如,把slot名称划分为类的属性,而不是实例的属性)。
slot声明可能出现在一个类树中的多个类中,但是,它们受到一些限制,除非你理解slot作为类级别描述符(这是我们将在本书最后一部分要学习的一种工具)的实现,否则要说明这些限制有些困难:
·如果一个子类继承自一个没有__slots__的超类,那么超类的__dict__属性总是可以访问的,使得子类中的一个__slots__无意义。
·如果一个类定义了与超类相同的slot名称,超类slot定义的名称版本只有通过直接从超类获取其描述符才能访问。
·由于一个__slots__声明的含义受到它出现其中的类的限制,所以子类将有一个__dict__,除非它们也定义了一个__slots__。
·通常从列出实例属性这方面来讲,多类中的slots可能需要手动类树爬升、dir用法,或者把slot名称当做不同的名称领域的政策:
当这种通用性可能的时候,slots可能最好当做类属性来对待,而不是试图让它们表现出与常规类属性一样。要了解关于slots的更多内容,参见Python的标准手册。此外,参见第38章中考虑到基于__slots__和__dict__存储的属性的一个示例。
要了解为什么通用程序可能需要关注slots的一个例子,请参阅上一章的多继承小节中的lister.py显示混入类示例;那里的一个提示描述了示例的slot内容。在这样一个试图通用地列出属性的工具中,slot用法需要额外的代码或者实现相应的政策,以通用地处理基于slot的属性。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论