Python实现尾调优化

Python实现尾调优化

在Python中使用 ‘return + 函数名()’ 可以实现尾调用,即调用某函数后立即结束当前函数。
但是Python最多只能尾调 1000 次,超出则会报错。


以下是通常的尾调示例:

def a(e):
	print('%s'%e)
	return a(e + 1)
a(1)

结果:

1
2
3
...
995
996
RecursionError: maximum recursion depth exceeded while calling a Python object

在尾调深度超过 1000 以后就会报错,无法进一步尾调。


一个牛人想出了解决方法

以下代码定义一个装饰器(适用于Python3+)

# 低版本Python改成 class TailRecurseException:
class TailRecurseException(BaseException):
    def __init__(self, args, kwargs):
        self.args = args
        self.kwargs = kwargs

def tail_call_optimized(g):
    """
    This function decorates a function with tail call
    optimization. It does this by throwing an exception
    if it is it's own grandparent, and catching such
    exceptions to fake the tail call optimization.

    This function fails if the decorated
    function recurses in a non-tail context.
    """
    def func(*args, **kwargs):
        f = sys._getframe()
        # 为什么是grandparent, 函数默认的第一层递归是父调用,
        # 对于尾递归, 不希望产生新的函数调用(即:祖父调用),
        # 所以这里抛出异常, 拿到参数, 退出被修饰函数的递归调用栈!
        if f.f_back and f.f_back.f_back \
                and f.f_back.f_back.f_code == f.f_code:
            # 抛出异常
            raise TailRecurseException(args, kwargs)
        else:
            while 1:
                try:
                    return g(*args, **kwargs)
                # 低版本Python改成 except TailRecurseException, e:
                except TailRecurseException as e:
                    # 捕获异常, 拿到参数, 退出被修饰函数的递归调用栈
                    args = e.args
                    kwargs = e.kwargs
    func.__doc__ = g.__doc__
    return func

然后上面的示例改成如下:

@tail_call_optimized
def a(e):
	print('%s'%e)
	return a(e + 1)
a(1)
# 实际使用时注意加停止调用的条件,否则会一直循环调用

更新_20200409:

新发现,如果尾调循环的入口函数没有设定形参,而循环内部的某个函数却设定了形参,则会报一个错误:

	return g(*args, **kwargs)
TypeError: calculatingTime() takes 0 positional arguments but 1 was given

我的也不知道是什么原因,但找到了 解决方法:

给入口函数设定一个带默认值的形参

def functionName(NULL=''):

这样就可以解决此类问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值