返回顶部
首页 > 资讯 > 后端开发 > Python >Python怎么开启尾递归优化
  • 551
分享到

Python怎么开启尾递归优化

2023-06-30 13:06:50 551人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

这篇文章主要讲解了“python怎么开启尾递归优化”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python怎么开启尾递归优化”吧!一般递归与尾递归一般递归:def nORMal_

这篇文章主要讲解了“python怎么开启尾递归优化”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python怎么开启尾递归优化”吧!

一般递归与尾递归

一般递归:

def nORMal_recursion(n):    if n == 1:        return 1    else:        return n + normal_recursion(n-1)

执行:

normal_recursion(5)5 + normal_recursion(4)5 + 4 + normal_recursion(3)5 + 4 + 3 + normal_recursion(2)5 + 4 + 3 + 2 + normal_recursion(1)5 + 4 + 3 + 35 + 4 + 65 + 1015

可以看到, 一般递归, 每一级递归都产生了新的局部变量, 必须创建新的调用栈, 随着递归深度的增加, 创建的栈越来越多, 造成爆栈?

尾递归

尾递归基于函数的尾调用, 每一级调用直接返回递归函数更新调用栈, 没有新局部变量的产生, 类似迭代的实现:

def tail_recursion(n, total=0):    if n == 0:        return total    else:        return tail_recursion(n-1, total+n)

执行:

tail_recursion(5, 0)tail_recursion(4, 5)tail_recursion(3, 9)tail_recursion(2, 12)tail_recursion(1, 14)tail_recursion(0, 15)15

可以看到, 尾递归每一级递归函数的调用变成"线性"的形式. 这时, 我们可以思考, 虽然尾递归调用也会创建新的栈, 但是我们可以优化使得尾递归的每一级调用共用一个栈!, 如此便可解决爆栈和递归深度限制的问题!

C中尾递归的优化

GCc使用-O2参数开启尾递归优化:

int tail_recursion(int n, int total) {    if (n == 0) {        return total;    }    else {        return tail_recursion(n-1, total+n);    }}int main(void) {    int total = 0, n = 4;    tail_recursion(n, total);    return 0;}

反汇编

$ gcc -S tail_recursion.c -o normal_recursion.S$ gcc -S -O2 tail_recursion.c -o tail_recursion.S gcc开启尾递归优化

对比反汇编代码如下(AT&T语法, 左图为优化后)

Python怎么开启尾递归优化

可以看到, 开启尾递归优化前, 使用call调用函数, 创建了新的调用栈(LBB0_3); 而开启尾递归优化后, 就没有新的调用栈生成了, 而是直接pop bp指向的_tail_recursion函数的地址(pushq %rbp)然后返回, 仍旧用的是同一个调用栈!

Python开启尾递归优化

cpython本身不支持尾递归优化, 但是一个牛人想出的解决办法:

实现一个 tail_call_optimized 装饰器

#!/usr/bin/env python2.4# This program shows off a python decorator(# which implements tail call optimization. It# does this by throwing an exception if it is# it's own grandparent, and catching such# exceptions to recall the stack.import sysclass TailRecurseException:    def __init__(self, args, kwargs):        self.args = args        self.kwargs = kwargsdef 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()        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)                except TailRecurseException, e:                    args = e.args                    kwargs = e.kwargs    func.__doc__ = g.__doc__    return func@tail_call_optimizeddef factorial(n, acc=1):    "calculate a factorial"    if n == 0:        return acc    return factorial(n-1, n*acc)print factorial(10000)

这里解释一下sys._getframe()函数:

sys._getframe([depth]):
Return a frame object from the call stack.
If optional integer depth is given, return the frame object that many calls below the top of the stack.
If that is deeper than the call stack, ValueEfror is raised. The default for depth is zero,
returning the frame at the top of the call stack.

即返回depth深度调用的栈帧对象.

import sysdef get_cur_info():    print sys._getframe().f_code.co_filename  # 当前文件名    print sys._getframe().f_code.co_name  # 当前函数名    print sys._getframe().f_lineno # 当前行号    print sys._getframe().f_back # 调用者的帧

更多关于sys._getframe的使用请看https://www.yisu.com/article/181387.htm

说一下tail_call_optimized实现尾递归优化的原理:

当递归函数被该装饰器修饰后, 递归调用在装饰器while循环内部进行, 每当产生新的递归调用栈帧时: f.f_back.f_back.f_code == f.f_code:, 就捕获当前尾调用函数的参数, 并抛出异常, 从而销毁递归栈并使用捕获的参数手动调用递归函数. 所以递归的过程中始终只存在一个栈帧对象, 达到优化的目的.

为了更清晰的展示开启尾递归优化前、后调用栈的变化和tail_call_optimized装饰器抛异常退出递归调用栈的作用, 我这里利用pudb调试工具做了动图:

开启尾递归优化前的调用栈

Python怎么开启尾递归优化

开启尾递归优化后(tail_call_optimized装饰器)的调用栈

Python怎么开启尾递归优化

通过pudb右边栏的stack, 可以很清晰的看到调用栈的变化.

感谢各位的阅读,以上就是“Python怎么开启尾递归优化”的内容了,经过本文的学习后,相信大家对Python怎么开启尾递归优化这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: Python怎么开启尾递归优化

本文链接: https://lsjlt.com/news/329396.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python怎么开启尾递归优化
    这篇文章主要讲解了“Python怎么开启尾递归优化”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python怎么开启尾递归优化”吧!一般递归与尾递归一般递归:def normal_...
    99+
    2023-06-30
  • Python开启尾递归优化的实现示例
    目录一般递归与尾递归一般递归:尾递归C中尾递归的优化Python开启尾递归优化一般递归与尾递归 一般递归: def normal_recursion(n): if n == ...
    99+
    2024-04-02
  • python怎么实现尾递归优化
    小编给大家分享一下python怎么实现尾递归优化,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!说明尾递归是指在函数返回时调用自身,return语句不能包含表达式。...
    99+
    2023-06-20
  • C++ 函数递归详解:尾递归优化
    递归定义及优化:递归:函数内部调用自身,解决可分解为更小子问题的难题。尾递归:函数进行所有计算后才进行递归调用,可优化为循环。尾递归优化条件:递归调用为最后操作。递归调用参数与原始调用参...
    99+
    2024-05-03
    c++ 递归
  • 详解Python如何实现尾递归优化
    目录一般递归与尾递归一般递归尾递归C中尾递归的优化Python开启尾递归优化一般递归与尾递归 一般递归 def normal_recursion(n): if n == 1:...
    99+
    2024-04-02
  • C++ 递归进阶:理解尾递归优化及其应用
    尾递归优化 (tro) 可提高特定递归调用的效率。它将尾递归调用转换为跳转指令,并将上下文状态保存在寄存器中,而不是堆栈上,从而消除对堆栈的额外调用和返回操作,提高算法效率。利用 tro...
    99+
    2024-04-30
    c++ 递归
  • 什么是python尾递归
    本篇内容主要讲解“什么是python尾递归”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“什么是python尾递归”吧!递归是啥递归函数大家肯定写过,学校上课的时...
    99+
    2024-04-02
  • C++ 递归函数的尾递归优化策略如何实现?
    尾递归优化策略通过将尾递归调用转换为循环,有效减少函数调用栈深度,防止栈溢出。优化策略包括:检测尾递归:检查函数中是否存在尾递归调用。将函数转换为循环:使用循环来代替尾递归调用,并维护栈...
    99+
    2024-04-17
    递归函数 尾递归优化 c++
  • C++ 递归与尾递归:性能差异和优化实践探讨
    c++++ 中标准递归会产生栈空间和时间开销,而尾递归不会。优化实践包括识别尾递归、转化为尾递归和启用编译器支持。尾递归比标准递归性能更高,因为它避免了创建额外活动记录和相关的开销。 ...
    99+
    2024-05-04
    c++ 递归 优化实践
  • C++ 函数尾递归优化的条件是什么?
    c++++ 中尾递归优化 (tco) 的条件如下:尾递归调用必须是函数的最后一个动作。函数的参数和局部变量在尾递归调用中必须保持不变。编译器必须支持 tco。实战案例中,使用 tco 将...
    99+
    2024-04-11
    c++ 函数尾递归优化
  • C++ 函数的递归实现:如何使用尾递归优化技术?
    递归函数的效率问题可以通过尾递归优化 (tc++o) 技术解决。c++ 编译器虽然不支持 tco,但可以通过 [__tail_recursive](https://en.cpprefer...
    99+
    2024-04-22
    c++ 递归
  • Python中使用装饰器来优化尾递归的示例
    尾递归简介 尾递归是函数返回最后一个操作是递归调用,则该函数是尾递归。 递归是线性的比如factorial函数每一次调用都会创建一个新的栈(last-in-first-out)通过不断的压栈,来创建递归, ...
    99+
    2022-06-04
    递归 示例 Python
  • Javascript尾递归编程怎么实现
    本篇内容介绍了“Javascript尾递归编程怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!尾递归编程思想递归是编程中必不可少的一环...
    99+
    2023-07-02
  • Python深层递归如何优化
    在Python中,深层递归可能会导致栈溢出的问题。为了优化深层递归,可以考虑以下几种方法:1. 尾递归优化:将递归函数转换为尾递归形...
    99+
    2023-08-15
    Python
  • python递归优化的方法是什么
    在Python中,递归函数的优化方法主要有以下几种:1、尾递归优化尾递归是指递归函数在递归调用时,最后一个操作是函数调用本身,可以通...
    99+
    2023-05-13
    python递归优化 python
  • Java的递归算法怎么优化
    优化递归算法可以通过以下方法来实现:1. 尾递归优化:尾递归是指递归函数在调用自身之后没有其他的操作,直接返回递归函数的结果。尾递归...
    99+
    2023-08-15
    Java
  • JavaScript调用栈、尾递归和手动优化的示例分析
    这篇文章给大家分享的是有关JavaScript调用栈、尾递归和手动优化的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。调用栈(Call Stack)调用栈(Call St...
    99+
    2024-04-02
  • oracle递归优化的方法是什么
    Oracle递归查询优化的方法主要有以下几个:1、使用WITH子句使用WITH子句可以将递归查询转换为非递归查询,提高查询效率。WI...
    99+
    2023-05-13
    oracle递归优化 oracle
  • php递归优化的方法是什么
    PHP递归优化的方法主要有以下几个:1. 尾递归优化:将递归函数转化为尾递归函数,可以减少函数调用栈的深度,提高函数的执行效率。尾递...
    99+
    2023-05-13
    php递归优化 php
  • python怎么实现递归
    这篇文章将为大家详细讲解有关python怎么实现递归,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。最简单的递归的实例  # -*- coding:ut...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作