什么是猴子补丁?

发布于 2024-10-31 18:53:24 字数 72 浏览 8 评论 0原文

我想了解什么是猴子补丁或猴子补丁?

这是否类似于方法/运算符重载或委托?

这些东西有什么共同点吗?

I am trying to understand, what is monkey patching or a monkey patch?

Is that something like methods/operators overloading or delegating?

Does it have anything common with these things?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

不念旧人 2024-11-07 18:53:24

不,它不像那些东西。它只是在运行时动态替换属性。

例如,考虑一个具有 get_data 方法的类。此方法执行外部查找(例如,在数据库或 Web API 上),并且类中的各种其他方法都会调用它。但是,在单元测试中,您不想依赖外部数据源 - 因此您可以使用返回一些固定数据的存根动态替换 get_data 方法。

因为 Python 类是可变的,而方法只是类的属性,所以您可以随心所欲地执行此操作 - 事实上,您甚至可以以完全相同的方式替换模块中的类和函数。

但是,正如评论者指出的那样,在猴子修补时要小心:

  1. 如果除了测试逻辑调用之外还有其他任何事情get_data 同样,它也会调用经过猴子修补的替代品,而不是原来的——这可能是好是坏。请小心。

  2. 如果存在某些变量或属性,在您替换它时也指向 get_data 函数,则此别名不会改变其含义,并将继续指向原始 get_data< /代码>。 (为什么?Python 只是将类中的名称 get_data 重新绑定到其他函数对象;其他名称绑定根本不受影响。)

No, it's not like any of those things. It's simply the dynamic replacement of attributes at runtime.

For instance, consider a class that has a method get_data. This method does an external lookup (on a database or web API, for example), and various other methods in the class call it. However, in a unit test, you don't want to depend on the external data source - so you dynamically replace the get_data method with a stub that returns some fixed data.

Because Python classes are mutable, and methods are just attributes of the class, you can do this as much as you like - and, in fact, you can even replace classes and functions in a module in exactly the same way.

But, as a commenter pointed out, use caution when monkeypatching:

  1. If anything else besides your test logic calls get_data as well, it will also call your monkey-patched replacement rather than the original -- which can be good or bad. Just beware.

  2. If some variable or attribute exists that also points to the get_data function by the time you replace it, this alias will not change its meaning and will continue to point to the original get_data. (Why? Python just rebinds the name get_data in your class to some other function object; other name bindings are not impacted at all.)

音栖息无 2024-11-07 18:53:24

MonkeyPatch 是一段扩展或修改的 Python 代码
运行时的其他代码(通常在启动时)。

一个简单的示例如下所示:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

来源: Zope wiki 上的 MonkeyPatch 页面。

A MonkeyPatch is a piece of Python code which extends or modifies
other code at runtime (typically at startup).

A simple example looks like this:

from SomeOtherProduct.SomeModule import SomeClass

def speak(self):
    return "ook ook eee eee eee!"

SomeClass.speak = speak

Source: MonkeyPatch page on Zope wiki.

安稳善良 2024-11-07 18:53:24

什么是猴子补丁?

简而言之,猴子修补是在程序运行时对模块或类进行更改。

使用示例

Pandas 文档中有一个猴子修补的示例:

import pandas as pd
def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

为了分解这个问题,首先我们导入我们的模块:

import pandas as pd

接下来我们创建一个方法定义,它在任何类定义的范围之外存在未绑定且自由的(因为区别是函数和未绑定方法之间毫无意义,Python 3 取消了未绑定方法):

def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

接下来我们只需将该方法附加到我们想要使用它的类:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

然后我们可以在该类的实例上使用该方法,并在完成后删除该方法:

df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

对于名称修改的警告

如果您正在使用名称修改(在属性前面添加双下划线,这会改变名称,我不建议这样做),您将不得不如果您这样做,请手动进行 name-mangle。由于我不推荐名称修改,因此我不会在这里演示。


测试示例

我们如何在测试中使用这些知识?

假设我们需要模拟对外部数据源的数据检索调用,该调用会导致错误,因为我们希望确保在这种情况下的正确行为。我们可以对数据结构进行猴子修补以确保这种行为。 (因此使用 Daniel Roseman 建议的类似方法名称:)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

当我们测试依赖于该方法引发错误的行为时,如果正确实现,我们将在测试结果中得到该行为。

只需执行上述操作就会在进程的生命周期中改变 <​​code>Structure 对象,因此您需要在单元测试中使用设置和拆卸来避免这样做,例如:(

def setUp(self):
    # retain a pointer to the actual real method:
    self.real_get_data = datasource.Structure.get_data
    # monkey patch it:
    datasource.Structure.get_data = get_data

def tearDown(self):
    # give the real method back to the Structure object:
    datasource.Structure.get_data = self.real_get_data

虽然上面的内容很好,使用 mock 库来修补代码可能是一个更好的主意,它比使用 mockpatch 装饰器更不容易出错。上面的,这将需要更多的代码行,因此有更多的机会引入错误,我还没有在 mock 中检查代码,但我想它以类似的方式使用猴子修补。)

What is a monkey patch?

Simply put, monkey patching is making changes to a module or class while the program is running.

Example in usage

There's an example of monkey-patching in the Pandas documentation:

import pandas as pd
def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class
df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

To break this down, first we import our module:

import pandas as pd

Next we create a method definition, which exists unbound and free outside the scope of any class definitions (since the distinction is fairly meaningless between a function and an unbound method, Python 3 does away with the unbound method):

def just_foo_cols(self):
    """Get a list of column names containing the string 'foo'

    """
    return [x for x in self.columns if 'foo' in x]

Next we simply attach that method to the class we want to use it on:

pd.DataFrame.just_foo_cols = just_foo_cols # monkey-patch the DataFrame class

And then we can use the method on an instance of the class, and delete the method when we're done:

df = pd.DataFrame([list(range(4))], columns=["A","foo","foozball","bar"])
df.just_foo_cols()
del pd.DataFrame.just_foo_cols # you can also remove the new method

Caveat for name-mangling

If you're using name-mangling (prefixing attributes with a double-underscore, which alters the name, and which I don't recommend) you'll have to name-mangle manually if you do this. Since I don't recommend name-mangling, I will not demonstrate it here.


Testing Example

How can we use this knowledge, for example, in testing?

Say we need to simulate a data retrieval call to an outside data source that results in an error, because we want to ensure correct behavior in such a case. We can monkey patch the data structure to ensure this behavior. (So using a similar method name as suggested by Daniel Roseman:)

import datasource

def get_data(self):
    '''monkey patch datasource.Structure with this to simulate error'''
    raise datasource.DataRetrievalError

datasource.Structure.get_data = get_data

And when we test it for behavior that relies on this method raising an error, if correctly implemented, we'll get that behavior in the test results.

Just doing the above will alter the Structure object for the life of the process, so you'll want to use setups and teardowns in your unittests to avoid doing that, e.g.:

def setUp(self):
    # retain a pointer to the actual real method:
    self.real_get_data = datasource.Structure.get_data
    # monkey patch it:
    datasource.Structure.get_data = get_data

def tearDown(self):
    # give the real method back to the Structure object:
    datasource.Structure.get_data = self.real_get_data

(While the above is fine, it would probably be a better idea to use the mock library to patch the code. mock's patch decorator would be less error prone than doing the above, which would require more lines of code and thus more opportunities to introduce errors. I have yet to review the code in mock but I imagine it uses monkey-patching in a similar way.)

就像说晚安 2024-11-07 18:53:24

根据维基百科

在 Python 中,仅术语“monkey patch”
指的是动态修改
运行时的类或模块,有动机
旨在修补现有的
第三方代码作为解决方法
不作为的错误或功能
你想要的。

According to Wikipedia:

In Python, the term monkey patch only
refers to dynamic modifications of a
class or module at runtime, motivated
by the intent to patch existing
third-party code as a workaround to a
bug or feature which does not act as
you desire.

浮生未歇 2024-11-07 18:53:24

第一:猴子补丁是一种邪恶的黑客(在我看来)。

它通常用于用自定义实现替换模块或类级别的方法。

最常见的用例是当您无法替换原始代码时,为模块或类中的错误添加解决方法。在这种情况下,您可以通过猴子修补将“错误”代码替换为您自己的模块/包内的实现。

First: monkey patching is an evil hack (in my opinion).

It is often used to replace a method on the module or class level with a custom implementation.

The most common usecase is adding a workaround for a bug in a module or class when you can't replace the original code. In this case you replace the "wrong" code through monkey patching with an implementation inside your own module/package.

他是夢罘是命 2024-11-07 18:53:24

Monkey 补丁只能用动态语言来完成,Python 就是一个很好的例子。在运行时更改方法而不是更新对象定义就是一个例子;类似地,在运行时添加属性(无论是方法还是变量)被视为猴子修补。这些通常是在使用没有源代码的模块时完成的,这样对象定义就不能轻易更改。

这被认为是不好的,因为这意味着对象的定义没有完全或准确地描述它的实际行为。

Monkey patching can only be done in dynamic languages, of which python is a good example. Changing a method at runtime instead of updating the object definition is one example;similarly, adding attributes (whether methods or variables) at runtime is considered monkey patching. These are often done when working with modules you don't have the source for, such that the object definitions can't be easily changed.

This is considered bad because it means that an object's definition does not completely or accurately describe how it actually behaves.

从﹋此江山别 2024-11-07 18:53:24

猴子补丁是在运行时重新打开现有的类或类中的方法并更改行为,应谨慎使用,或者仅在确实需要时才使用它。

由于 Python 是一种动态编程语言,类是可变的,因此您可以重新打开它们并修改甚至替换它们。

Monkey patching is reopening the existing classes or methods in class at runtime and changing the behavior, which should be used cautiously, or you should use it only when you really need to.

As Python is a dynamic programming language, Classes are mutable so you can reopen them and modify or even replace them.

淤浪 2024-11-07 18:53:24

什么是猴子修补?猴子修补是一种用于在运行时动态更新一段代码行为的技术。

为什么使用猴子补丁?它允许我们在运行时修改或扩展库、模块、类或方法的行为,而无需
实际修改源码

结论 猴子补丁是一项很酷的技术,现在我们已经学会了如何在 Python 中做到这一点。然而,正如我们所讨论的,它有它的
其自身的缺点,应谨慎使用。

What is monkey patching? Monkey patching is a technique used to dynamically update the behavior of a piece of code at run-time.

Why use monkey patching? It allows us to modify or extend the behavior of libraries, modules, classes or methods at runtime without
actually modifying the source code

Conclusion Monkey patching is a cool technique and now we have learned how to do that in Python. However, as we discussed, it has its
own drawbacks and should be used carefully.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文