Python 编程别再用递归了

递归函数使用起来非常酷,简洁优雅,可以用来炫耀编程技巧。但是,在大多数情况下,递归函数具有非常高的时间和空间复杂性,我们应该避免使用它。更好的解决方案之一是在可能的情况下使用动态规划,对于能够分解为子问题的问题,动态规划可能是最佳方法。然而某些动态规划的状态转移方程不太容易定义。

今天分享 Python 的另一种牛逼的技术--闭包,可以用来作为替代递归函数。它可能不会胜过动态规划,但在思考方面要容易得多。换句话说,由于思想的抽象,我们有时可能难以使用动态规划,但是使用闭包会容易一些。

什么是 Python 闭包?

首先,让我使用一个简单的示例来说明什么是 Python 中的闭包。看下面的函数:

在一个函数内部定义另外一个函数,并返回这个函数,这种特性就是闭包。检查 outer 函数的返回值,可以确认这是一个函数。

闭包这种特性能做什么呢?因为函数返回的是一个函数,我们就可以调用这个函数,比如:

不过我们一般会这么使用闭包,这样太丑陋了。你可能会好奇这个跟递归有什么关系?别着急,让我们慢慢体会闭包的牛逼之处。

闭包内的变量访问

从前述的运行结果来看,inner 函数可以访问 outer 函数内部定义的变量 x,但是却无法修改它,下面的代码运行时会报错:

为了解决这个问题,我们可以加上 nonlocal 关键字,告诉 inner 函数,这不是一个本地变量:

有没有发现,x 的值竟然被保存了下来,每次调用一下,就增加了 1,这就是闭包的妙处。

用闭包来替换递归

利用上述闭包会保留调用结果的特性,我们可以用这个来替换递归,比如利用闭包计算斐波那契数列:

可以这样调用来生产斐波那契数列:

而使用递归方法计算斐波那契数列的方法如下所示:

把之前的闭包版本封装一下:

这样使用 fib_closure(20) 就可以计算出结果:

现在使用 IPython 来测试下这两者的性能:

可以看出两差相差近 1000 倍,这还只是计算到第 20 个数的情况下,如果计算到 100,那使用递归会计算很久甚至无法计算出来。

闭包的其他用处

Python 的闭包不仅仅用于替换递归,还有很多场景可以使用闭包。比如学生成绩的分类函数:

学生成绩数据:

现在需要根据学生成绩进行分类,通常情况下我们会写多个函数来进行分类,而分类的标准又会经常变化,这时候闭包就很方便了:

如果分类标准变化,直接个性函数的参数即可,主要代码逻辑不变,如果想查找成绩分类为 A 的学生,只需要调用 grade_A(students) 即可:

闭包使用上述分类函数很容易修改且更加易读。

最后的话

本文介绍了一种称为 Python 闭包的技术。在大多数情况下,可以使用它来重写递归函数,并且在很大程度上优于后者。

实际上,从性能的角度来看,闭包可能不是某些问题的最佳解决方案,尤其是在使用动态规划的情况下。但是,闭包写起来要容易一些,比递归性能高。当我们对性能不是很敏感时,有时写动态计划会有点浪费时间,但是闭包可能就足够了。

闭包也可以用来定义一些逻辑相同但命名不同的函数,比如本文中的分类函数,在这些情况下,它更加整洁而优雅,更加易读。

下次试试闭包吧,别用效率低下的递归了。

(0)

相关推荐

  • 25 条超棒的 Python 一行代码

    自从用Python编写第一行代码以来,就被它的简单性.出色的可读性和特别流行的一行代码所吸引. 在下面,我将给大家介绍并解释一些Python一行程序. 可能有些你还不知道,但对你未来的Python项目 ...

  • 读完这篇算法总结,我感觉自己距离谷歌更近了

    读完这篇算法总结,我感觉自己距离谷歌更近了

  • Python|动态规划问题--斐波那契数列

    斐波那契数列斐波那契数列其表达式如下: 递归算法通过公式我们不难看出,其第一项和第二项为1,当x>=3时,斐波那契数列的第x项就等于其前两项的和.所以我们可以得出代码如下:public stat ...

  • 一行 Python 代码实现并行,骚技能!

    当我用Python写第一行代码的那一天,我着迷于简单性,流行性及其著名的单行代码. 1.交换两个变量 # a = 4 b = 5a,b = b,a# print(a,b) >> 5,4 让 ...

  • PHP递归与迭代

    在 PHP 中,我们经常会遇到这样的情况:在面临一个庞大的问题时,需要把这个庞大的问题拆分成各个细小的单元,解决了每个细小单元的问题,这个庞大的问题便迎刃而解了.递归与迭代就是这种思想的体现. PHP ...

  • Python|递归函数之斐波那契数列

    上一期小编主要针对def函数的运用进行了简单的讲解,本期将会深入探讨def函数的另一种特别有用的函数(递归函数),其定义:如果一个函数在内部调自身,这个函数就是递归函数,递归函数的优点在于其定义简单, ...

  • 零基础学Python:函数精讲

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 1. 位置参数与关键字参数 尽管这种方式很常见,但是位置参数的一个弊端是必须熟记每个位置的参 ...

  • 全栈Python 编程必备

    据说:2019年, 浙江信息技术高考可以考python了:2018年, Python 进入了小学生的教材:2018年, 全国计算机等级考试,可以考python 了:据外媒报道,微软正考虑添加 Pyth ...

  • 免费提供普通高中信息技术学科电子教材,系统内置Python编程工具,人教信息技术教学系统来啦

    蒸汽机是农业社会进入工业社会的催化剂,计算机是工业社会进入信息社会的通行证:人工智能时代,与机器人协作将成为人们的必备技能,而程序正是人与机器对话的主要语言.学习编程不等于当程序员,但它是我们接触前沿 ...

  • Python编程

    Python编程 IDE:集成开发工具 python,java,c,c++,c#,javascript,php,R,ruby, Python(目前有两个大版本Python2-Python3)的集成开发 ...

  • Python编程常用的十大语法和代码汇总

    C.1.1 Python的"Hello World" [输入] source_code/appendix_c_python/example00_helloworld.py prin ...

  • 收藏,7个学习Python编程的最佳开源库!

    来源丨网络 1.learn-python3 这个存储库一共有19本Jupyter笔记本.它涵盖了字符串和条件之类的基础知识,然后讨论了面向对象编程,以及如何处理异常和一些Python标准库的特性等.每 ...

  • 这 14 个短代码,蕴含着丰富的 Python 编程思维

    价值前瞻 105篇原创内容 公众号 来源:Python实用宝典 今天给大家带来一些30秒就能学会的代码片段,这些代码潜力无限,蕴含了丰富的python编程思维,应用领域非常广泛,而且学起来非常简单. ...

  • Python编程必备工具,推荐这五个!

    python是编程入门者非常不错的选择,现在不少程序员都开始转行到python行列中,因为简单易学.应用范围广,不过学习python还是需要一个好的工具,否则会吃不少苦头,那么Python编程必备5大 ...

  • Python编程基础:序列类型概述

    https://m.toutiao.com/is/eYtBNf7/ 序列首先是一种数据存储方式,用来存储一系列的数据.序列存储数据的主要特点就是数据在内存空间中是连续存储的,例如字符串abc(字符串属 ...

  • Python灰帽子:黑客与逆向工程师的Python编程之道中文(PDF)

    内容简介  · · · · · · <Python灰帽子>是由知名安全机构Immunity Inc的资深黑帽Justin Seitz主笔撰写的一本关于编程语言Python如何被广泛应用于黑 ...