2013-03-07 42 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子句中包装第三个条件,具体取决于您想实现的目标。