2013-03-07 41 views
1

我有裝飾器跟蹤一些遞歸函數。我想知道返回到try塊的方式。我試過while循環,但它不適合我,因爲我的函數是遞歸的,任何人都可以給我一個想法如何處理? 的問題是當函數change_t拋出一個異常,我想繼續EXCUTE我 try塊Python預期異常後返回嘗試塊

這裏是我的裝飾和功能

正確的結果:

,- change_t([9, 7, 5], 44) 
| ,- change_t([9, 7, 5], 35) 
| | ,- change_t([9, 7, 5], 26) 
| | | ,- change_t([9, 7, 5], 17) 
| | | | ,- change_t([9, 7, 5], 8) 
| | | | | ,- change_t([7, 5], 8) 
| | | | | | ,- change_t([7, 5], 1) 
| | | | | | | ,- change_t([5], 1) 
| | | | | | | | ,- change_t([], 1) 
| | | | | | ,- change_t([5], 8) 
| | | | | | | ,- change_t([5], 3) 
| | | | | | | | ,- change_t([], 3) 
| | | | | | | ,- change_t([], 8) 
| | | | ,- change_t([7, 5], 17) 
| | | | | ,- change_t([7, 5], 10) 
| | | | | | ,- change_t([7, 5], 3) 
| | | | | | | ,- change_t([5], 3) 
| | | | | | | | ,- change_t([], 3) 
| | | | | | ,- change_t([5], 10) 
| | | | | | | ,- change_t([5], 5) 
| | | | | | | | ,- change_t([5], 0) 
| | | | | | | | `- [] 
| | | | | | | `- [5] 
| | | | | | `- [5, 5] 
| | | | | `- [5, 5] 
| | | | `- [7, 5, 5] 
| | | `- [7, 5, 5] 
| | `- [9, 7, 5, 5] 
| `- [9, 9, 7, 5, 5] 
`- [9, 9, 9, 7, 5, 5] 

這是我得到了什麼: 它我停止後,我期望有一個例外

change_t([9, 7, 5], 44) 
,- change_t ([9, 7, 5], 44) 
| ,- change_t ([9, 7, 5], 35) 
| | ,- change_t ([9, 7, 5], 26) 
| | | ,- change_t ([9, 7, 5], 17) 
| | | | ,- change_t ([9, 7, 5], 8) 
| | | | | ,- change_t ([7, 5], 8) 
| | | | | | ,- change_t ([7, 5], 1) 
| | | | | | | ,- change_t ([5], 1) 
| | | | | | | | ,- change_t ([], 1) 
| | | | | | `- 1 
| | | | | `- 1 
| | | | `- 1 
| `- 8 
`- 8 
`- 17 
`- 26 
`- 35 
`- 44 
44 
+1

我不太明白你的問題,但我有一種感覺,你可能正在尋找'終於'。 – 2013-03-07 11:50:39

+1

我認爲你也應該重新評估你在裝飾者中遇到的異常。 – poke 2013-03-07 11:52:19

+0

我嘗試了finally塊:但是當我調用value = self.f(* args,** kwargs)時,它會進行另一次遞歸調用 – user1968057 2013-03-07 11:54:47

回答

2

正如我在評論中所說的,您需要重新評估異常,以便原始函數可以實際捕獲並繼續。你想僅僅通過一個內部的,除了處理程序,以減少縮進,這樣你就不會在左端漲過頭:

class traced(object): 
    indent =0 
    def __init__(self,f): 
     self.__name__=f.__name__ 
     self.indent=0 
     self.f=f   
    def __call__(self,*args,**kwargs): 
     string=""   
     if kwargs: 
      l=[] 
      for (key, value) in kwargs.items(): 
       l.append(str(key) + "=" + str(value)) 
      a=', '.join(l) 
      string = '('+a+')'    
     else: 
      l=[] 
      for value in args: 
       l.append(str(value)) 
      a=', '.join(l) 
      string = '('+a+')'  
     print('| ' * traced.indent + ',- '+ self.__name__+' '+string) 
     try: 
      traced.indent+=1 
      value = self.f(*args,**kwargs)     
     except Exception: 
      traced.indent-=1 # <-- only decrement by one 
      raise    # <-- reraise the exception so the original function can catch it 
     traced.indent-=1 
     print('| '* traced.indent + "`- "+ repr(value))   
     return value 

然後它的工作原理:

>>> change_t([9, 7, 5], 44) 
,- change_t ([9, 7, 5], 44) 
| ,- change_t ([9, 7, 5], 35) 
| | ,- change_t ([9, 7, 5], 26) 
| | | ,- change_t ([9, 7, 5], 17) 
| | | | ,- change_t ([9, 7, 5], 8) 
| | | | | ,- change_t ([7, 5], 8) 
| | | | | | ,- change_t ([7, 5], 1) 
| | | | | | | ,- change_t ([5], 1) 
| | | | | | | | ,- change_t ([], 1) 
| | | | | | ,- change_t ([5], 8) 
| | | | | | | ,- change_t ([5], 3) 
| | | | | | | | ,- change_t ([], 3) 
| | | | | | | ,- change_t ([], 8) 
| | | | ,- change_t ([7, 5], 17) 
| | | | | ,- change_t ([7, 5], 10) 
| | | | | | ,- change_t ([7, 5], 3) 
| | | | | | | ,- change_t ([5], 3) 
| | | | | | | | ,- change_t ([], 3) 
| | | | | | ,- change_t ([5], 10) 
| | | | | | | ,- change_t ([5], 5) 
| | | | | | | | ,- change_t ([5], 0) 
| | | | | | | | `- [] 
| | | | | | | `- [5] 
| | | | | | `- [5, 5] 
| | | | | `- [5, 5] 
| | | | `- [7, 5, 5] 
| | | `- [7, 5, 5] 
| | `- [9, 7, 5, 5] 
| `- [9, 9, 7, 5, 5] 
`- [9, 9, 9, 7, 5, 5] 
[9, 9, 9, 7, 5, 5] 

最後我將清理裝飾了一下,使其更加簡潔清楚自己在做什麼:

class traced(object): 
    indent = 0 

    def __init__(self, f): 
     self.__name__ = f.__name__ 
     self.f = f 

    def __call__(self, *args, **kwargs): 
     if kwargs: 
      l = [str(key) + '=' + str(value) for key, value in kwargs.items()] 
     else: 
      l = list(map(str, args)) 
     print('| ' * traced.indent + ',- {0} ({1})'.format(self.__name__, ', '.join(l))) 
     try: 
      traced.indent += 1 
      value = self.f(*args,**kwargs)     
     finally: 
      traced.indent -= 1 

     print('| ' * traced.indent + '`- ' + repr(value)) 
     return value 

在這裏,我簡化了整個論證聚合使用列表理解。此外,我使用字符串格式來使格式更清晰。這樣你也可以將你必須放在列表內容中的括號(你在兩種情況下都是這樣做的)混合在一起。並且,如果您沒有真正查看異常而重新評估異常,我們不需要首先捕捉異常,只需確保我們調整finally塊中的縮進。

而實際上,爲什麼要檢查要麼可變參數關鍵字參數?只要接受兩者:

l = list(map(str, args)) 
l.extend([str(key) + '=' + str(value) for key, value in kwargs.items()]) 
+1

您也可以將'except'語句更改爲'finally'語句。如果遞減是在「finally」塊中(並且之後不再重複),那麼其工作原理將完全相同,並且代碼的意圖可能更清楚。 – Blckknght 2013-03-07 12:07:55

+0

謝謝你的幫助!我是一個蟒蛇noobie ......但是加薪是什麼? – user1968057 2013-03-07 12:17:41

+0

沒有參數的單個'raise'會再次引發當前異常。因此,在「except」塊內,它將重新引發由「except」塊捕獲的異常。它基本上將異常傳遞到下一個級別。 – poke 2013-03-07 12:19:29

0

當一個exceptio n被提出,控制從它被提出的代碼中被放棄。而是將其交給捕獲該異常的第一個catch塊或主解釋器循環。

你的代碼看看:

if a==0: 
    return [] 
elif len(l)==0: 
    raise ChangeException() 
elif l[0]>a: 
    return change_t(l[1:],a) 

當第三個條件是真實的,即l[0]>a,當L的長度爲1會發生什麼事?然後在下一次調用中,即return change_t(l[1:],a)它會引發一個異常,除了主循環外,任何人都不會發現異常:這就是爲什麼你的代碼失敗。您需要在try catch子句中包裝第三個條件,具體取決於您想實現的目標。