1

我跟踪了装饰器的一些递归函数。我想知道返回 try 块的方法。我已经尝试过while循环,但它对我不起作用,因为我的函数是递归的,谁能告诉我如何处理它?问题是当函数 change_t 引发异常时,我想继续执行我的 try 块

这是我的装饰器和功能

正确的结果:

,- 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
4

2 回答 2

2

正如我在评论中所说,您需要重新引发异常,以便原始函数实际上可以捕获并继续。您只想在 except 处理程序中将缩进减少一个,这样您就不会在左侧太远:

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()])
于 2013-03-07T12:04:40.030 回答
0

当引发异常时,控制权将从引发异常的代码中放弃。而是将其移交给捕获该异常的第一个 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 子句中,具体取决于您想要实现的目标。

于 2013-03-07T12:04:17.603 回答