13 猴子补丁在 Python 中的加载次序问题
本节我们就来解决如何在 Python 中打补丁的问题。
1. 猴子补丁的加载次序问题
在第 11 篇博客中,我们提到了应用猴子补丁时可能存在的问题。具体地说,如果需要被打补丁的模块已经被导入并被其他代码使用,那么它可能已经在自己的名称空间中创建了一个被打补丁的目标函数的本地引用。因此,尽管猴子补丁可以正常工作,但是仍然无法覆盖这种原始函数已经导入,并过通过本地引用直接访问原始函数的情况。
本节我们就来解决如何在 Python 中打补丁的问题。
在第 11 篇博客中,我们提到了应用猴子补丁时可能存在的问题。具体地说,如果需要被打补丁的模块已经被导入并被其他代码使用,那么它可能已经在自己的名称空间中创建了一个被打补丁的目标函数的本地引用。因此,尽管猴子补丁可以正常工作,但是仍然无法覆盖这种原始函数已经导入,并过通过本地引用直接访问原始函数的情况。
前面我们说道过 Python 中使用猴子补丁典型情景之一就是使用模拟库来帮助执行单元测试,本节我们先把补丁和模块导入的相对次序问题放一放,先来看看如何使用 wrapt 模块辅助单元测试。
在之前 10 篇博客中,我们几乎完整的讨论了装饰器的实现。现在我们将焦点从装饰器转移到猴子补丁上来。
通常在Python中永远不应该做的事情之一就是编写猴子补丁。但有些人认为这是一种有用的必需品,你可能无法避免修补第三方代码中的错误。其他人则可能会争辩说,现在有这么多的软件是开源的,所以您应该简单地向上游包维护人员提交一个补丁。
在上一篇文章中,我们对作为函数闭包实现的装饰器与前文描述的通用装饰器进行了性能比较。本节我们继续我们的性能测试,看看装饰一个类方法时,不同实现方式的性能表现。
前面我们探讨了装饰器的实现方式,并实现了一个所谓的通用装饰器模式,并用它创建了一个类似 Java 的 @synchronized 装饰器作为使用示例。本节我们来看看不同的装饰器实现方式的性能问题。在这篇关于装饰器的实现性能这篇文章之后,我们将开始深入探讨如何实现代理,它是通用装饰器机制中的基础组件。
在前一篇文章中,我们描述了如何使用新的通用装饰器模式来实现Python的 @synchronized 同步原语装饰器。在Java提供的两个同步机制中,同步方法和同步原语,目前为止我们只实现了同步方法。本文将描述如何将其扩展为上下文管理器,从而等效的实现Java的同步原语。