2

随着时间的推移,我发现需要重写stdlibPython 中的几个方法以克服限制或添加一些缺失的功能。

在所有情况下,我都添加了一个包装器函数,并用我的包装器替换了模块中的原始方法(包装器调用了原始方法)。

我为什么这样做?只是为了确保对该方法的所有调用都使用我的新版本,即使这些是从其他第三方模块调用的。

我知道猴子补丁可能是一件坏事,但我的问题是,如果你小心使用它是否有用?意思是:

  • 您仍然调用原始方法,以确保更新原始模块时不会丢失任何内容
  • 您没有改变方法的原始“含义”

例子:

  • 为 python 日志记录模块添加着色支持
  • 使open()在使用文本模式时能够识别 Unicode BOM 掩码
  • 添加日志记录支持os.system()subprocess.Popen()- 让您输出到控制台或/并重定向到另一个文件。
  • 实现您的平台上缺少的方法,例如os.chown()Windowsos.lchown()上缺少的方法。

做这样的事情在我看来是体面的替代,但我想看看其他人是如何看待它们的,特别是什么应该被视为可接受的猴子补丁,什么不是。

4

2 回答 2

7

这些东西似乎都不需要猴子补丁。他们似乎都有更好、更强大和更可靠的解决方案。

添加日志处理程序很容易。没有猴子补丁。

固定打开是这样完成的。

from io import open

那很简单。没有补丁。

登录到os.system()? 我认为一个简单的“包装器”功能会比一个复杂的补丁好得多。此外,我会使用subprocess.Popen,因为这是推荐的替代品。

添加缺少的方法来掩盖操作系统差异(如os.chown())似乎是 try/except 的更好用途。但这只是我。我喜欢显式而不是隐式。

总的来说,我仍然看不到猴子补丁的充分理由。

我不想被锁定在遗留代码(如os.system),因为我太依赖于我的猴子补丁。


“子类”的概念适用于模块和类。您可以轻松编写自己的模块,这些模块 (a) 导入和 (b) 扩展现有模块。然后,您可以使用新模块,因为它们提供了额外的功能。你不需要猴子补丁。

即使这些是从其他第三方模块调用的

可怕的想法。您可以通过更改内置功能轻松破坏另一个模块。如果您已阅读其他模块并确定猴子补丁不会损坏,那么您发现的就是这个。

  1. “其他”模块应该有定制的空间。它应该有一个“依赖注入”或策略设计模式的位置。好想法。

  2. 一旦你找到了这个,可以修复“其他”模块以允许这种定制。它可能就像解释如何修改对象的文档更改一样简单。它可能是用于插入您的自定义的构造的附加参数。

  3. 然后,您可以将修改后的模块提供给作者,看看他们是否会支持您对其模块的小幅更新。许多类可以使用额外的帮助来支持“依赖注入”或扩展策略设计。

如果您还没有阅读其他模块并且不确定您的monkeypatches 是否工作......好吧......我们仍然希望monkeypatches 不会破坏任何东西。

于 2010-08-10T15:05:41.923 回答
3

Monkeypatching 有时可能是“最无害的”——大多数情况下,当您需要测试代码时,该代码使用的子系统设计的可测试性不佳(不支持依赖注入 &c)。在这些情况下,您将在您的测试工具中进行猴子补丁(非常暂时,幸运的是),并且几乎总是使用模拟或假货进行猴子补丁以隔离测试(即,使它们成为单元测试,而不是集成测试)。

这种“糟糕但可能更糟糕”的用例似乎不适用于您的示例——它们都可以通过编辑应用程序级代码来调用您的适当包装函数(例如,myos.chown而不是裸函数os.chown)并放入您自己的中间模块(例如myown)中的包装器函数位于应用程序级代码和标准库(或您因此包装的第三方扩展——在这方面标准库没有什么特别之处)之间。

当“应用程序级代码”并非真正在您的控制之下时,可能会出现一种问题情况——它是您不想修改的第三方子系统。尽管如此,我发现在这种情况下,修改第三方子系统以调用包装器(而不是直接调用标准库函数)从长远来看效率更高——当然,您将更改提交给第三方的维护者有问题的子系统,他们将您的更改滚动到其子系统的下一个版本中,每个人的生活都会变得更好(包括您在内,因为一旦您的更改被接受,他们将定期得到维护和其他人的测试!-)。

(作为旁注,这样的包装器也可能值得作为差异提交给标准库,但这不同的情况,因为标准库的发展非常缓慢和谨慎,特别是在 Python 2 行将永远不会再发展,因为 2.7 是该行的最后一行,并且已被冻结)。

当然,所有这些都以开源文化为前提。如果出于某些神秘的原因,您正在使用封闭源代码的第三方子系统,因此您无法维护,那么您处于另一种情况,猴子修补可能是较小的邪恶(但这只是因为失去战略控制的邪恶通过信任您无法维护的代码来进行开发本身就是一个更大的邪恶;-)。我从来没有发现自己在这种情况下使用了一个既封闭源代码又本身用 Python 编写的第三方包(如果后一种情况不支持你的猴子补丁对你没有好处;-)。

请注意,这里“闭源”的工作定义非常严格:例如,即使是微软 12 多年前也分发了库的源代码,例如带有 Visual C++ 的 MFC(当时他们的产品被称为)——闭源是因为您无法重新分发他们的资源,但是,您手头确实有资源,所以当您遇到一些可怕的限制或错误时,您可以修复它(并将更改提交给他们以供将来发布,以及将您的更改发布为一个差异,只要它绝对不包含他们受版权保护的代码——不是微不足道的,而是可行的)。

Monkeypatching 远远超出了这种方法是“最不邪恶”的严格限制,这是动态语言用户经常犯的错误——小心不要自己落入这个陷阱!

于 2010-08-10T15:30:51.683 回答