代码之家  ›  专栏  ›  技术社区  ›  Philipp Chapkovski

是否可以恢复(返回到旧方法)python monkey补丁

  •  0
  • Philipp Chapkovski  · 技术社区  · 7 年前

    我使用了一个专门的python模块,它在运行时修改了一些django类方法(也称为monkey修补)。如果我需要这些“旧”版本,有没有可能“回到”它们,覆盖猴子补丁?

    比如,导入这些类的初始版本?

    以下是如何在包中进行修补的示例:

    from django.template.base import FilterExpression
    
    def patch_filter_expression():
        original_resolve = FilterExpression.resolve
        def resolve(self, context, ignore_failures=False):
            return original_resolve(self, context, ignore_failures=False)
    
        FilterExpression.resolve = resolve
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Martijn Pieters    7 年前

    这取决于补丁做了什么。MonkeyPatching没有什么特别的,它只是为一个名称分配一个不同的对象。如果再也没有其他东西引用旧值,那么它就从Python的内存中消失了。

    import target.module
    
    _original_function = target.module.target_function
    
    def new_function(*args, **kwargs):
        result = _original_function(*args, **kwargs)
        return result * 5
    
    target.module.target_function = new_function
    

    这里是名字 target_function target.module new_function ,但原始对象仍可用为 _original_function

    如果在函数中执行此操作,则原始文件可以作为 也一样。对于您的特定示例,您可以通过以下方式获取原始文件:

    FilterExpression.resolve.__closure__[0].cell_contents
    

    def closure_mapping(func):
        closures, names = func.__closure__, func.__code__.co_freevars
        return {n: c.cell_contents for n, c in zip(names, closures)}
    
    original_resolve = closure_mapping(FilterExpression.resolve)['original_resolve']
    

    否则,您可以告诉python importlib.reload() 以下内容:

    import target.module
    importlib.reload(target.module)
    

    修补 from target.module import target_function 创建对 当前命名空间中的对象,不需要重新加载原始命名空间 模块将更新任何其他直接引用。您必须手动更新这些其他引用,或者重新加载它们的名称空间。