我使用一个专用的python模块,该模块在运行时修改了一些Django类方法(又名Monkey-patching)。如果我需要这些“旧”版本,是否有可能“回来”以覆盖猴子补丁?
例如,要导入这些类的初始版本?
这是一个如何在软件包中进行修补的示例:
read/update
答案 0 :(得分:2)
这取决于补丁的功能。 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
的命名空间中仍然可用。修补代码。
如果在函数中完成此操作,则原始文档也可以作为 closure 使用。对于您的特定示例,您可以通过以下方式获取原件:
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)
这将刷新模块名称空间,将所有全局名称“重置”为在导入时设置的名称(保留所有其他名称)。
但是请注意,任何直接引用 patched 对象(例如您的类对象)的代码都看不到更新后的对象!这是因为from target.module import target_function
在当前名称空间中创建了对target_function
对象的新引用,并且对原始target.module
模块的重载不会更新任何其他直接引用。您必须手动更新这些其他引用,或者也重新加载它们的名称空间。