python - 在 Python 中修补一个类的所有实例

标签 python monkeypatching

我正在使用 Python 3.5.1。 我写了一个库,在某些情况下(当文件直接运行时,即 __name__ == '__main__')我想在其中一个类中装饰某些方法。它应该装饰所有可以创建的实例。我想以一种非侵入性的方式进行,即理想情况下,我的库中的类不需要任何特殊代码。

一段时间后,我设法实现了这样的东西,满足了我的要求:

def patch(clazz, name, replacement):

    def wrap_original(orig):
        # when called with the original function, a new function will be returned
        # this new function, the wrapper, replaces the original function in the class
        # and when called it will call the provided replacement function with the
        # original function as first argument and the remaining arguments filled in by Python

        def wrapper(*args, **kwargs):
            return replacement(orig, *args, **kwargs)

        return wrapper

    orig = getattr(clazz, name)
    setattr(clazz, name, wrap_original(orig))

def replacement_function(orig, self, ... other argumnents ...):
    # orig here is the original function, so can be called like this:
    # orig(self, ... args ...)
    pass

patch(mylib.MyClass, 'method_name', replacemment_function)

令人惊讶的是,这段代码有效,虽然我还没有用类方法测试它,但我现在不需要它。它还会修补在修补之前创建的实例,尽管我还不确定它是否好;d

上面的代码可以说是很难的,我在写完之后需要一段时间来了解它的工作方式,以便写出解释注释。我想要更简单的东西。

问题:Python 库中是否有任何东西可以使这样的代码变得不必要,它已经实现了我正在做的事情,但更好?

最佳答案

方法是在查找实例时动态创建的;实例没有所有方法的副本,而是 descriptor protocol从类中获取函数并根据需要将它们绑定(bind)到实例。这就是为什么 monkeypatching 类在这里起作用的原因; instance.method_name 将在执行属性查找时找到 mylib.MyClass.method_name

默认库中没有执行您在此处执行的操作的任何内容,不,因为不同的代码可能需要不同的处理委托(delegate)返回旧方法的模式。

您的方法看起来非常接近 how the Mercurial project支持函数包装,因为原始函数被传递到包装器中。

关于python - 在 Python 中修补一个类的所有实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37103476/

相关文章:

python libtorrent 使用磁铁 URI 时我应该等待元数据多长时间?

python map 与 itertools.map : Make the iterator version behave like the former

python - 循环列表并打印字符串的这些元素

python - 将数字添加到 scikit-learn 的 CountVectorizer 的 stop_words

Python:强制每个导入重新加载

objective-c - 有什么方法可以猴子修补或调配 NSArray(或其他类集群)?

ruby - 您如何影响 Ruby 代码的加载顺序?

python - 快速将数组分配给长度相等的 n 个 bin

ruby - 如何使用模块对类进行猴子修补?