Python中的对象回滚、写时复制、版本代理等

2 投票
2 回答
601 浏览
提问于 2025-04-16 10:44

前提:给定一个Python对象obj,我想把它传递给某个随机函数。当这个函数完成后,我需要能够将obj恢复到它最初的状态。此外,不能对obj进行任何实际的修改,因为其他代码可能还需要访问它的原始状态。


理想的解决方案应该在大多数情况下快速处理,因为通常情况下一个大的obj只会稍微被修改。而在不常见的情况下,如果需要将obj恢复到之前的状态,性能就没那么重要了。

这些要求和简单复制对象的粗暴解决方案是不同的:在大多数情况下,这种方法会非常慢,而在不常见的回滚情况下却会非常快。

这个解决方案应该允许处理对象的代码像对待普通对象一样对待它。这包括给它赋予各种属性,甚至是自定义类。显然,解决方案需要考虑整个对象树。可能需要做一些妥协。我目前考虑过的一些限制包括要求非基本类型都继承自一个特殊的基类,禁止使用字典和列表,而用元组和自定义字典类来替代等等。某些重大妥协可能是可以接受的。

我已经在这个问题上工作了一段时间,想看看更有经验的Python高手有什么想法和建议。


编辑:Fred的回答让我意识到一个缺失的要求:不能对原始的obj进行任何修改,因为原始状态也是很重要的。

2 个回答

0

看看这个备忘录设计模式

这里有一个Python的例子

1

其实我现在已经实现了两个解决方案,看到没有其他答案,我就来分享一个吧。

最简单的解决方案是使用按需复制。假设我们有一个代理对象P,它指向一个真实对象OP会有一个__getattr__方法,这样当你尝试访问P.x时,它会从O.x复制数据,并同时把这个数据存储到P.x。这样一来,以后再访问P.x时,就不会再调用__getattr__了,而对P.x的修改也不会影响到原来的O

这里面有一些实现细节:

  • 需要维护一个属性列表,记录从P中删除的属性;如果PO合并,删除的属性也必须从O中删除。
  • 为任何支持的数据类型(比如dictlist等)编写自定义的深度复制程序,确保在复制的dictlist等中,把所有的O对象替换成代理P
  • 如果需要的话,编写ProxyDictProxyList等。
  • 确保代理链(即代理的代理)能够正常工作。这基本上是为了避免在代理的代理需要检查某个属性是否存在时产生副作用。
  • 实现将代理向下合并到被代理对象中的方法,并完全拆分,复制被代理对象中剩余的数据。
  • 尽管如此,和效果的复杂性相比,这个解决方案非常容易理解:代理只需复制任何被访问的数据。

    撰写回答