【问题标题】:Is monkeypatching stdlib methods a good practice in Python? [closed]Monkeypatching stdlib 方法是 Python 中的一个好习惯吗? [关闭]
【发布时间】:2010-08-10 14:58:44
【问题描述】:

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

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

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

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

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

例子:

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

【问题讨论】:

    标签: python word-wrap monkeypatching


    【解决方案1】:

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

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

    通过这种方式修复打开。

    from io import open
    

    这很容易。没有补丁。

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

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

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

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


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

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

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

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

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

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

    如果您尚未阅读其他模块并且不确定确定您的猴子补丁是否可以正常工作......好吧......我们仍然希望猴子补丁不会破坏任何东西。

    【讨论】:

    • 谢谢,我稍微更新了描述,解释了我为什么要覆盖标准库——主要是为了防止我修补大量文件甚至第三方代码以调用“改进” ''' 方法。
    【解决方案2】:

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

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

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2020-08-25
      • 2015-08-03
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 1970-01-01
      • 2023-01-06
      • 1970-01-01
      • 2013-03-30
      相关资源
      最近更新 更多