2011-08-19 51 views
1

我遇到了一個情況,我正在處理一段代碼,其中我對遠程對象發出了更改(這是我無法複製到在克隆上工作),然後向遠程對象請求新狀態下的某些操作,並通過一系列相反的命令恢復我對它所做的所有更改。 問題是,如果在所有這些更改中遇到錯誤,我希望能夠回滾到目前爲止所做的所有更改。在沒有極端標識的情況下在python中維護代碼的可回滾流程

是來到我腦海中最適合的解決方案是Python的try-最後的工作流程,但它是相當成問題時,命令序列長:

try: 
    # perform action 
    try: 
     # perform action 
     try: 
      # ... 
     finally: 
      # unroll 
    finally: 
     # unroll 
finally: 
    # unroll 

這樣,更命令我需要更深我的縮進和嵌套變得越來越少,我的代碼可讀性越差。 我曾考慮過其他一些解決方案,例如維護一個堆棧,其中對於每個命令我推送一個回滾操作,但這可能會變得相當複雜,而且我不喜歡將綁定方法推入堆棧。 我也考慮過增加一個計數器來執行我所執行的每個動作,然後在一個單獨的計算機上根據計數器決定是否需要回滾,但同樣,這種代碼的可維護性會變得很痛苦。

我搜索「交易」和「回滾」時遇到的大多數匹配都與數據庫相關,並且不適合更通用的代碼... 任何人都有一個好主意,以便如何系統性地變平這個暴行?

+0

你爲什麼不喜歡堆棧方法?看起來像一個完美的方式來做到這一點。 – carlpett

回答

5

會不會Context Manager objectswith聲明改善情況?特別是如果您可以使用Python語言版本,其中with語句支持多個上下文表達式,例如2.7或3.x.這裏有一個例子:

class Action(object): 
    def __init__(self, count): 
     self.count = count 
    def perform(self): 
     print "perform " + str(self.count) 
     if self.count == 2: 
      raise Exception("self.count is " + str(self.count)) 
    def commit(self): 
     print "commit " + str(self.count) 
    def rollback(self): 
     print "rollback " + str(self.count) 
    def __enter__(self): 
     perform() 
     return self 
    def __exit__(self, exc_type, exc_value, traceback): 
     if exc_value is None: 
      self.commit() 
     else: 
      self.rollback() 

with Action(1), Action(2), Action(3): 
    pass 

你必須在你的代碼移到了一套「交易」類,如Action以上,其中如果終止在__enter__()方法執行,並要執行的動作通常情況下,您可以保證將調用相應的__exit()__方法。

請注意,我的示例並不完全對應於您的;您必須調整__enter__()方法中要執行的操作以及with語句正文中要執行的操作。在這種情況下,你可能想使用的語法如下:

with Action(1) as a1, Action(2) as a2: 
    pass 

爲了能夠從with語句體中訪問Action對象。

+0

你能舉一個例子嗎? – Izkata

+0

@Izkata:我用一個例子更新了我的答案。 –

+0

哇,這是一個非常優雅的解決方案... 雖然,如果我需要執行兩個動作之間的一些中間計算,我仍然需要嵌套「與」的權利? 順便說一下,Python 2.6的語法是否相同?或者,您的意思是2.7之前的每個「with」的單個動作? – immortal

相關問題