- 译者序
- 前言
- 第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 各部分练习题的解答
- 作者介绍
- 封面介绍
为什么使用装饰器(重访)
就像大多数语言功能一样,装饰器也有优点和缺点。例如,从负面的角度讲,类装饰器有两个潜在的缺陷:
类型修改
正如我们所见到的,当插入包装器的时候,一个装饰器函数或类不会保持其最初的类型——其名称重新绑定到一个包装器对象,在使用对象名称或测试对象类型的程序中,这可能会很重要。在单体的例子中,装饰器和管理函数的方法都为实例保持了最初的类类型;在跟踪器的代码中,没有一种方法这么做,因为需要有包装器。
额外调用
通过装饰添加一个包装层,在每次调用装饰对象的时候,会引发一次额外调用所需的额外性能成本——调用是相对耗费时间的操作,因此,装饰包装器可能会使程序变慢。在跟踪器代码中,两种方法都需要每个属性通过一个包装器层来指向;单体的示例通过保持最初的类类型而避免了额外调用。
类似的问题也适用于函数装饰器:装饰和管理器函数都会导致额外调用,并且当装饰的时候通常会发生类型变化(不装饰的时候就没有)。
也就是说,这二者都不是非常严重的问题。对于大多数程序来说,类型差异问题不可能有关系,并且额外调用对速度的影响也不显著;此外,只有当使用包装器的时候才会产生后一个问题,且这个问题常常可以忽略,因为需要优化性能的时候可以直接删除装饰器,并且添加包装逻辑的非装饰器解决方案也会导致额外调用的问题(包括我们将在第39章学习的元类)。
相反,正如我们在本章开始所见到的,装饰器有3个主要优点。与前面小节的管理器(即辅助)函数解决方案相比,装饰器提供:
明确的语法
装饰器使得扩展明确而显然。它们的@比可能在源文件中任何地方出现的特殊代码要容易识别,例如,在单体和跟踪器实例中,装饰器行似乎比额外代码更容易被注意到。此外,装饰器允许函数和实例创建调用使用所有Python程序员所熟悉的常规语法。
代码可维护性
装饰器避免了在每个函数或类调用中重复扩展的代码。由于它们只出现一次,在类或者函数自身的定义中,它们排除了冗余性并简化了未来的代码维护。对于我们的单体和跟踪器示例,要使用管理器函数的方法,我们需要在每次调用的时候使用特殊的代码——最初以及未来必须做出的任何修改都需要额外的工作。
一致性
装饰器使得程序员忘记使用必需的包装逻辑的可能性大大减少。这主要得益于两个优点——由于装饰是显式的并且只出现一次,出现在装饰的对象自身中,与必须包含在每次调用中的特殊代码相比较,装饰器促进了更加一致和统一的API使用。例如,在单体示例中,可能更容易忘了通过特殊代码来执行所有类创建调用,而这将会破坏单体的一致性管理。
装饰器还促进了代码的封装以减少冗余性,并使得未来的维护代价最小化。尽管其他的编码结构化工具也能做到这些,但装饰器使得这对于扩展任务来说更自然。
然而,这三个优点还不是使用装饰器语法的必需的原因,装饰器的用法最终还是一个格式选择。也就是说,大多数程序员发现了一个纯粹的好处,特别是它作为正确使用库和API的一个工具。
我还记得类中的构造函数函数的支持者和反对者也有过类似的争论——在介绍__init__方法之前,创建它的时候通过一个方法手动地运行一个实例,往往也能实现同样的效果(例如,X=Class().init())。然而,随着时间的流逝,尽管这基本上是一个格式的选择,但__init__语法也变成了广泛的首选,因为它更为明确、一致和可维护。尽管这应该由你来决定,但装饰器似乎把很多同样的成功摆到了桌面上。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论