2016-11-16 61 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