python之路第五篇之递归(进阶篇:续:经典例子剖析)
递归
在函数内部,可以调用其他函数;
如果一个函数在内部调用自身本身,这个函数就是递归函数。
例如,我们来计算阶乘:
n! = 1 x 2 x 3 x ... x n,
用函数f1(n)表示,可以看出:
f1(n) = n! = 1 x 2 x 3 x ... x (n-1) x n
= (n-1)! x n = f1(n-1) x n
所以,f1(n)可以表示为 n x f1(n-1),只有n=1时需要特殊处理。
于是,f1(n)用递归的方式写出来就是:
def f1(n):
if n==1:
return 1
return n * f1(n - 1)
上面就是一个递归函数。执行结果如下:
>>> f1(1)
1
>>> f1(3)
6
>>> f1(10)
3628800
那么,利用函数编写如下数列:
斐波那契数列指的是这样一个数列
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,
610,987,1597,2584,4181,6765,10946,17711,28657,46368 ...
实现代码如下:
def func(arg1,arg2):
if arg1 == 0:
print arg1, arg2
arg3 = arg1 + arg2
print arg3
func(arg2, arg3)
func(0,1)
执行结果如下:(“....”代表省略)
.....
26863810024485359386146727202142923967616609318986952340123175997617981700247881689338369654483356564191827856161443356312976673642210350324634850410377680367334151172899169723197082763985615764450078474174626
Traceback (most recent call last):
.....
334151172899169723197082763985615764450078474174626
Traceback (most recent call last):
File "<stdin>", line 1, in <module> #有报错
......
为什么上面有报错,难道是程序错了?其实不是,程序没错,因为“斐波那契数” 规律是前两个数相加
等于后面一个数,而程序一直不断这样执行下去,最终达到系统默认临界值,当然程序也就出错了
接下来,我们把程序再改改,我们让“不断循环的第三个值”(即arg3)大于1000的时候 返回一个值,
看看这个时候的效果,直接看下面代码:
def func1(arg1,arg2):
if arg1 == 0:
#print arg1,arg2
pass
arg3 = arg1 + arg2
if arg3 > 1000:
return arg3
func1(arg2,arg3)
result = func1(0,1)
print result
你们觉得上面打印的结果是什么?
看下面执行结果:
>>> print result
None
这是为什么,苦苦熬了这么多年,终于等到你,>~< ...(哈哈,开个玩笑)
上面代码分解如下:
def func1(arg1,arg2):
#arg1 = 0 ,arg2 = 1,第2次:arg1 = 1,arg2 = 1,第3次:arg1 = 1,arg2 = 2,
第4次:arg1 = 2,arg2 = 3,
if arg1 == 0: #满足条件,开始执行
#print arg1,arg2
pass #不做任何处理
arg3 = arg1 + arg2 #走到这一步,arg3 = 0 + 1 = 1,第2次:arg3 = 1 + 1 = 2,
第3次,arg3 = 1 + 2 = 3,第4次:arg3 = 2 + 3 = 5, .... 执行到第18次....
if arg3 > 1000: #第一次循环不符合条件,绕开return arg3,而继续往下执行;....
假设执行到第18次时符合条件,那么就会执行下面的代码,即 return arg3 会被执行!!!
return arg3
#第一次循环不执行,2,3,4次都一样不执行;.....,假设第18次时符合条件,并且执行
了return arg3,重点来了!!!!,这个时候我们都知道,函数体中,一个值被return,
那么这个函数的生命周期也就结束,不再往下执行,也就意味着下面的func1(arg2,arg3)
没有被执行.
func1(arg2,arg3)
#自身调用第2个和第3个的值,即第1次为:1 ,1 第2次为1,2,第3次:2,3 第4次:3,5 ....
假设执行到第18次,这个时候没有被执行,因为上面return的出现,函数生命周期已经结束
(重点!!:分析:既然18次时符合条件,并且return arg3,函数直接出去了,大家不妨想想,
那么在出去之前,它的上一次执行,也就是第17次并没有在func1(arg2,arg3)这一步,将这个
函数的值return(返回)给func1(arg1,arg2),也就意味着,17次没有返回,而18次时,
函数生命周期也已经结束!之后执行函数外面的操作,result = func1(arg1,arg2),print result,
接着往下看:
大家都知道,如果要将一个函数赋值给一个变量,假设这么赋值:result = func1(“值”,“值”),
那么这个函数肯定会有一个返回值,同时赋值给这个变量,由于17次没有return func1(arg2,
arg3)给func1(arg1,arg2),18次时函数结束,那么这个函数的默认返回值就是None(即空值)
那么赋值给这个变量和打印这个变量也就是None
同时大家记住一句话:python 函数默认是从上往下执行
result = func1(0,1) #第一次开始执行,赋值!第18次赋值,这个时候是None
print result #第1,2,3,4都不执行,因为这个是在函数外,只有函数结束后才行,....
第18次,这里打印了最终值"None"
大家是否已经知道
上面的代码改成下面这样:
def func1(arg1,arg2):
if arg1 == 0:
#print arg1,arg2
pass
arg3 = arg1 + arg2
if arg3 > 1000:
return arg3
return func1(arg2,arg3) #这里return ,所有有值
执行结果如下:
>>> result = func1(0,1)
>>> print result
1597
return 返回值(经典例子):
你们认为下面的result 结果是什么? 10000???NO,NO,NO
def n4():
return "10000"
def n3():
n4()
def n2():
n3()
def n1():
n2()
result = n1()
print result
返回值为None
为什么?
请听分解:当我们最终print result 时,result = n1(), n1函数调用n2, n2函数调用n3,
n3函数调用n4,而当n3调用n4时,(n4函数有返回值),并没有return n4(),意味着n3是None,
因此n2函数在调用n3时,由于n3是None,,同时n3本身也没有return给n2,(就算return给n2了,
也是None,哈哈)所以最终返回就是None
这个例子是不是很经典?好了,今天很晚了,就分享到这里,因为白天上班,没什么时间写,也就只能晚上
写了(ps,现在是凌晨2点18分),下次继续新的内容!
python之路第五篇之递归(进阶篇:续:经典例子剖析)的更多相关文章
- python之路第五篇之模块和加密算法(进阶篇:续)
模块 Python中,如果要引用一些内置的函数,该怎么处理呢?在Python中有一个概念叫做模块(module) 简单地说,模块就是一个保存了Python代码的文件. 模块分类: 1)内置模块 2)自 ...
- Python之路(第五篇) Python基本数据类型集合、格式化、函数
一.变量总结 1.1 变量定义 记录某种状态或者数值,并用某个名称代表这个数值或状态. 1.2 变量在内存中的表现形式 Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是 ...
- python之路第五篇之装饰器:(进阶篇)
装饰器: 学前必备知识: def f1(): print "f1" f1() #表示函数执行 f1 #表示函数,指向内存地址 f1 = lambda x: x + 1 f1() # ...
- Python之路,进程、线程、协程篇
本节内容 进程.与线程区别 cpu运行原理 python GIL全局解释器锁 线程 语法 join 线程锁之Lock\Rlock\信号量 将线程变为守护进程 Event事件 queue队列 生产者 ...
- python之路十五
CSS position 属性 定义和用法position 属性规定元素的定位类型.说明这个属性定义建立元素布局所用的定位机制.任何元素都可以定位,不过绝对或固定元素会生成一个块级框,而不论该元素本身 ...
- Python之路第五天,基础(6)-模块
模块 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合.而对于一个复杂的功能来,可能需要多个 ...
- python学习三十五天函数递归的用法
python函数递归就是自己调用自己,无限循环,但是python限制了调用的次数1000次,就会终止,递归用在栏目分类,采集程序比较多,下面简单说函数递归用法和实例 1,函数递归用法 def func ...
- python之路《五》字符串的操作
python的里的字符串的操作是可以说是最常见也是最实用的 我们通常使用双引号来表示字符串" "创建字符串很简单,定义一个变量就可以了 1 name = 'my name \t i ...
- Python之路【第十七篇】Django进阶篇
规范 确立规范的好处: 代码可读性高 方便代码的定位极其查找 为以后代码扩容带来便利 场景: 在多个APP的场景下,单个app的URL函数功能较多的时候,我们可以通过以下方法来解决. 把Views写成 ...
随机推荐
- SQL Server 2014 64位版本链接32位Oracle数据库
问题背景: 刚进入公司不久的BI新手,最近接部门的一个交接项目,需要在SQL Server上通过openquery来获取Oracle数据库的数据.各种配置,各种设置折腾了一周之久.在此,将自己的问题解 ...
- spring mvc:exclude-mapping错误提示
今天搭建一个java web项目时,增加了一个登录的拦截器,主要功能就是未登录的用户无法访问系统的任何页面. 先说明下我的web项目springmvc的版本以及刚开始配置的拦截器: springmvc ...
- 基于大数据的电影网站项目开发之CentOS的安装(一)
一.下载VMware并安装,至于安装教程从网上搜索进行参考 二.下载系统镜像文件,这里使用的是CentOS-6.5-x86_64-bin-DVD1.iso 三.安装镜像文件 运行VMware work ...
- C# 文件的上传和下载
本文主要介绍一下,在APS.NET中文件的简单上传于下载,上传是将文件上传到服务器的指定目录下,下载是从存入数据库中的路径,从服务器上下载. 1.上传文件 (1)页面代码 <table alig ...
- UTF-8笔记170330
unicode 为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言.跨平台进行文本转换.处理的 UTF-8使用可变长度字节来储存 Unicode字符,例如ASCII字母继续使用1字节储 ...
- 201521123084 《Java程序设计》第4周学习总结
第4周作业-面向对象设计与继承 1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 总结: (1)学会了如何给类和方法进行简单的注释: (2)学 ...
- 201521123054《Java程序设计》第8周学习总结
1. 本周学习总结 2. 书面作业 List中指定元素的删除(题目4-1) 1.1 实验总结 每次删除时下标需要-1:原理如图 统计文字中的单词数量并按出现次数排序(题目5-3) 2.1 伪代码(简单 ...
- 201521123095 《Java程序设计》第6周学习总结
1.本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖面 ...
- 201521123072《java程序设计》第四次总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.11.2 使用常规方法总结其他上课内容 一些小的方法归纳: 通过 instanceof 可以判断父类引用所引用的对象实例的实际类 ...
- 201521123113 《Java程序设计》第4周学习总结
1.本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 设计类的技巧:类名和方法名要能够体现他们的职责,类名首字母要大写 如何识别一个类 方法.属性的 ...