2016-11-16 55 views
1

我正在设计一个面向对象的数据结构,从用户的角度来看应该很简单,例如通过方法链接(又名Fluent interface)。但是,每个更改只应在对象上暂时执行:在该链中,但不超出该链。
下面是一个简单的例子,做工作像预期一样:在方法链接过程中临时保留对对象的更改

class C: 
    def __init__(self, num): 
     self.sum = num 

    def add(self, num=0): 
     self.sum += num 
     return self 

number = C(23) 
number.add(7).add(12).sum 
# 42 
number.sum 
# 42 (but I expect: 23) 

在这种情况下,.add()使得永久变化number。然而,永久性的变化只可能是这样的:

# This is the only way how a user should make permanent changes: 
number = number.add(4).add(12) 

临时范围,我在寻找一种方式的链条被终止后,回到老版本的number。在绝望的边缘,我能想到的丑陋解决方案,如“实例复制”的:

class C2: 
    def __init__(self, num): 
     self.sum = num 

    def add(self, num=0): 
     self2 = C2(self.sum) # or equivalently: self2 = copy.deepcopy(self) 
     self2.sum += num 
     return self2 

number = C2(23) 
number.add(7).add(12).sum 
# 42 
number.sum 
# 23 

然而,实际工作中类和对象与我的工作包含大量的数据,属性,方法,甚至子类。所以我们应该避免在每一种方法中拷贝实例,除了它涉及丑陋的代码。

有没有办法解决这个问题,通过(静静地)在链的第一个元素上创建一个副本一次?或者通过摧毁链条末端所做的任何更改? (需要注意的是现实世界的“变化”涉及许多不同,可交换不仅仅是增加数量等方法)

接受的解决方案应该执行必要的操作内部,即不打扰用户界面:

# These are NOT accepted solutions: 
number.copy().add(4).add(12) 
number.add(4).add(12).undo() 

如果除了自我复制之外没有其他直接的解决方案,问题将会是:这样做的最优雅的方式是维持代码可读性并保持内存使用率低的最优方法是什么?例如,通过自我复制功能来装饰每种类别的方法?

+0

我不明白该对象如何自动检测“临时范围”的结束 - 除非可能通过编写自己的基于python的语言,甚至是...... FWIW,所有“流畅的接口“到目前为止,我所看到的实现方式都是对对象进行变异或返回副本。 –

回答

1

相反modyfing在其上调用该方法的对象,返回修改后的副本:

class C: 
    def __init__(self, num): 
     self.sum = num 

    def add(self, num=0): 
     return C(self.sum + num) 

number = C(23) 
assert number.add(7).add(12).sum == 42 
assert number.sum == 23 

有关详细信息在存储器上这个解决方案处理,看到这个帖子的评论。此解决方案是解决您的问题的标准方法。

+0

对不起,这个解决方案已经在问题中给出了。 – Martin

+0

然后我告诉你这是标准做法,不是肮脏的黑客攻击。 –

+0

我知道这是许多appliations的标准。但它是否也是大型实例的推荐(或唯一)策略?恐怕会大大增加内存使用量:S或者python会在链终止时自动删除所有实例吗? – Martin