Python 中的简单通用运行时猴子补丁?

Easy generic runtime monkey patching in Python?

有时我想对小问题进行小修复,仅用于测试或内部目的。

例如,我想在 sphinx.writers.html5.HTML5Translator.visit_literal_block.

中将 self.builder.current_docname 替换为 node.source

这样做的(优雅)方法是复制粘贴应该应用补丁的方法,然后修改我必须修改的小东西,然后用新方法覆盖原始方法。在这种情况下,我会有很多导入,我必须在本地 copy/paste 整个方法(糟糕的 SSOT 是糟糕的)。

相反,我想写这样的东西:

from monkey import ReMonkeyPatcher # Fake...
from sphinx.writer.html5 import HTML5Translator

# Override the class's method
ReMonkeyPatcher(HTML5Translator, 'self.builder.current_docname', 'node.source')

# Profit...

我读过 here,Python 的反射特性允许 运行-time hack inspectast。所以我写了这个:

def monkey_replace(function, search, replace):
    source = inspect.getsource(function)
    while code[0].isspace():
        code = textwrap.dedent(code)

    code = code.replace(search, replace)
    ast_tree = ast.parse(code)
    compile(ast_tree, '<string>', mode='exec')

    mod = {}
    exec(code, mod) # <-- Here is the issue...
    method = mod[function.__name__]
    replace_function(function, method) # Doesn't know how to do that yet

主要问题是 exec(code, mod) 缺少上下文。要在 any/most 情况下工作,它必须在原始函数(导入...)的上下文中执行。

有什么优雅的方法吗?

在Python monkey-patching中非常容易。正如您在 post 中所说: 因为没有受保护的变量,你可以简单地覆盖你想要修补的函数:

HTMLTranslator.builder.current_docname = node.source