递归
在函数内部,可以调用其他函数;
如果一个函数在内部调用自身本身,这个函数就是递归函数。
例如,我们来计算阶乘:
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" ===============================

递归1.什么是递归 recursion 递归      递归的定义--------在个一个函数里再调用这函数本身      在一个函数里再调用这个函数本身,这种魔性的使用函数的方式就叫做递归。      递归的最大深度——997    一个函数在内部调用自己 递归的层数在python里是有限制的 997/998层2.层数可以修改 sys模块 1 import sys #python限制在997/998
2 sys.setrecursionlimit(10000000) #可以修改
3 COUNT = 0
4 def func(): #recursion 递归
5 global COUNT
6 COUNT += 1
7 print(COUNT)
8 func()
9
10 func()3.解耦要完成一个完整的功能,但这个功能的规模要尽量小,并且和这个功能无关的其他代码应该和这个函数分离
1.增强代码的重用性
2.减少代码变更的相互影响
4.实例一,求年龄 1 #写递归函数必须要有一个结束条件
2 #sj
3 #1 sj egon + 2 n=1 age(1) = age(2) + 2
4 #2 egon wusir + 2 n=2 age(2) = age(3) + 2
5 #3 wusir + 2 n=3 age(3) = age(4) + 2
6 #4 40 n=4 age(4) = 40
7
8 def age(n):
9 if n == 4:
10 return 40
11 return age(n+1)+2
12
13 # age(1) #46
14 # def age(1):
15 # return 46
16 # age(1)=age(2)+2=age(3)+2+2=age(4)+2+2+2
17 # def age(2):
18 # return 44
19 #
20 # def age(3):
21 # return 42
22 #
23 # def age(4):
24 # if 4 == 4:
25 # return 405.实例二,求阶乘1 #求阶乘 n = 7 7*6*5*4*3*2*1
2 def func(n):
3 if n == 1:
4 return 1
5 else:
6 return n*func(n-1)
7
8 ret = func(4)
9 print(ret)
10
11 # #n = 4
12 # def func(4):
13 # return 24
14 # 4*3*2*1
15 # #n = 3
16 # def func(3):
17 # return 6
18 #
19 # #n = 2
20 # def func(2):
21 # return 2
22 #
23 # #n = 1
24 # def func(n):
25 # if n == 1:
26 # return 16.实例三,递归遍历目录和文件#!/usr/bin/python #coding:utf8 import os def dirlist(path, allfile): filelist = os.listdir(path) 列出目录下的文件 for filename in filelist: filepath = os.path.join(path, filename) 为文件添加绝对路径 if os.path.isdir(filepath): 如果文件为目录 dirlist(filepath, allfile) 继续递归 else: allfile.append(filepath) 不是文件就将路径放置列表中 return allfile print dirlist("/home/yuan/testdir", []) 【完】
-------------------

一、嵌套函数

  1、嵌套函数简单的理解可以看作是在函数的内部再定义函数,实现函数的“私有”。

  2、特点:

      <1> 函数内部可以再次定义函数。

      <2> 只有被调用时才会执行(外部函数被调用后,被嵌套函数调用才有效)。

  3、实例如下:

#!/usr/bin/env python3
#-*- coding:utf-8 -*- def func1():
print('hello world!')
def func2():
print('everyone...') func1() # 输出:hello world! ,此时func2未被调用并不执行

  4、然而嵌套函数并一定就是长这样,不信,继续往下看...

    为了更直观,我直接放出几种情形的案例,如下:

 1 #!/usr/bin/env python3
2 #-*- coding:utf-8 -*-
3
4 #情形1
5 name = 'cc'
6 def func1():
7 name = 'sc'
8 print(name)
9 def func2():
10 #name = 'df'
11 print(name)
12 func2()
13 func1() #输出:sc df,当第10行被注释时,输出:sc sc,
14 # 嵌套函数中的变量层层调用,当前函数中没有便向上一级函数查找
15
16 #情形2
17 age = 21
18 def func1():
19 def func2():
20 print(age) #输出:18,当前函数中并没有定义(‘第二层局部变量’)age,向第一层找
21 age = 18 #与func2位于同一层,‘第一层局部变量’
22 func2()
23 print(func1(),age) #输出:None ,21,此时,函数外输出的age只能是全局变量
24
25 #情形3
26 age = 21
27 def func1():
28 def func2():
29 print(age)
30 func2()
31 #age = 18
32 func1() #当31行不被注释时,运行会报错,打印age时会混淆全局age和局部age
33 #当31行被注释时,输出: 21,此时func2调用全局age
34
35 #情形4
36 age = 21
37 def func1():
38 global age #声明全局变量
39 def func2():
40 print('func2中的:',age) #输出>>func2中的: 21, age此时引用的是36行的全局变量
41 func2()
42 age = 18 #由于已经声明age是全局变量,所以此处的重新赋值就是对全局修改
43 func1()
44 print('全局中的:',age) #输出>>全局中的: 18, 变量age在函数func1中被修改
45
46 #情形5
47 age = 21
48 def func1():
49 global age
50 def func2():
51 print('func4中的:',age) #输出>>func2中的: 18, age此时引用的是47行的全局变量
52 age = 18 #由于已经声明age是全局变量,所以此处的重新赋值就是对全局修改
53 func2()
54 func1()
55 print('全局中的:',age) #输出>>全局中的: 18, 变量age在函数func1中被修改
'''
情形4和情形5的区别在于age变量的修改在程序中的执行顺序,在func2调用前还是在func2调用之后,
如果是在func2调用前修改age,则func2中输出的则是修改后的;如果是在func2调用后修改age,则func2中
输出的就是未修改时的全局变量age,所以两者func2函数中输出的age值不同,但最后的全局输出相同。
'''
 

二、递归函数

  1、定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。

  2、实例:  

def calc(n):
n = n // 2
print(n) # 输出:9 4 2 1 0 0 0 .... //到1000层结束调用
calc(n) # 重复调用自身 calc(19)

   查看默认调用层次的方法:

# -*-coding:utf-8 -*-
import sys print(sys.getrecursionlimit()) #查看递归默认限制层数,默认是1000

  3、递归调用的过程

#递归的执行过程
def func_re(n):
n = n // 2 # 地板除,商保留整数
print(n)
if n > 0:
func_re(n)
print(n)
func_re(13)
'''
python中递归执行的逻辑是一层层调用,再一层层退出,可通过调试断点查看
6
3
1
0
0
1
3
6
'''

  4、到这里,我们可以总结下递归的特性了:

    <1> 必须要有明确的终止条件

    <2> 每进入更深一层递归时,问题规模相比上次都应有所减少

    <3> 递归效率不高,层次过多会导致栈溢出

  5、了解了递归调用的过程,那么如果我不想它一直调用下去,而是满足某一条件就返回,不再执行了呢?该怎么做呢?

    实例如下:

def calc(n,count):
'''
:param n: 需要进行递归的对象
:param count: 计数器
:return: 条件不成立时,返回最终值
'''
print(n,count)
if count < 5: #运行第五次时退出
return calc(n//2,count+1) #每一层接收它下一层的值,return必不可少,否则倒数第三层无法接收倒数第二层的返回值
else:
return n # 最终结果返回到倒数第二层(即上一个return),只执行一次
func = calc(199,1)
print('res运算第五次时的结果:',func) # 输出>>res运算第五次时的结果: 12.4375

    当然,递归的用处不止于此,二分查找就是递归很好的应用:

data1 = [1,23,43,54,654,4544,34523]
def search(data1,find_num):
print(data1)
if len(data1) > 1:
middle = len(data1)//2
if data1[middle] == find_num:
print('找到了',data1[middle])
elif data1[middle]>find_num:
print('要找的数在%s左边'%data1[middle])
return search(data1[middle],find_num)
else:
print('要找的数在%s右边'%data1[middle])
return search(data1[middle], find_num)
else:
if data1[0] == find_num:
print('找到了',data1[0])
else:
print('你要找的数不在列表中')
search(data1,54)

三、高阶函数

  1、定义:变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,

       这种函数称之为高阶函数。

  2、满足高阶函数的条件(任意一个):
    <1> 接受一个或多个函数作为输入
    <2> return 返回另外一个函数
 3、实例如下:
#!/usr/bin/env python3
#-*- coding:utf-8 -*- # 接受一个或多个函数作为输入
def func(a,b):
return a-b def func2(x):
return x f = func2(func)
print(f(5,2)) # 3 # reyurn 返回另外一个函数
def func3(a,b):
return abs,a,b # abs为内置方法 res = func3(3,-5)
print(res) # 输出:(<built-in function abs>, 3,-5),一个元组
print(res[0](res[1]+res[2])) #输出:2
 =======================
 
 

python 递归进阶操作方法的更多相关文章

  1. 用Python递归解决阿拉伯数字转为中文财务数字格式的问题(2)--打开思路的一种方法

    几天前自己写了个将阿拉伯数字转为中文财务数字的程序.用的递归,不幸的是它是树形递归. 虽然实际过程中不太可能出现金额数字大到让Python递归栈溢出,但是始终是一块心病,这玩意终究在理论上是受限制的. ...

  2. Python文件常用操作方法

    Python文件常用操作方法 一.对File对象常用操作方法: file= open(file, mode='r', buffering=-1, encoding=None, errors=None, ...

  3. python 字符串常用操作方法

    python 字符串常用操作方法 python 字符串操作常用操作,如字符串的替换.删除.截取.赋值.连接.比较.查找.分割等 1.去除空格 str.strip():删除字符串两边的指定字符,括号的写 ...

  4. Python递归_打印节点信息

    Python递归_打印节点信息 递归特性:1.必须由一个明确的结束条件2.每次进入更深一层递归时,问题规模相比上一次递归都应该有所减少3.递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用时 ...

  5. python最全学习资料:python基础进阶+人工智能+机器学习+神经网络(包括黑马程序员2017年12月python视频(百度云链接))

    首先用数据说话,看看资料大小,达到675G 承诺:真实资料.不加密,获取资料请加QQ:122317653 包含内容:1.python基础+进阶+应用项目实战 2.神经网络算法+python应用 3.人 ...

  6. Python 列表(List)操作方法详解

    Python 列表(List)操作方法详解 这篇文章主要介绍了Python中列表(List)的详解操作方法,包含创建.访问.更新.删除.其它操作等,需要的朋友可以参考下   列表是Python中最基本 ...

  7. python学习大全:python基础进阶+人工智能+机器学习+神经网络

    首先用数据说话,看看资料大小,达到675G承诺:真实资料.不加密.(鉴于太多朋友加我QQ,我无法及时回复,) 方便的朋友给我点赞.评论下,谢谢!(内容较大,多次保存) [hide]链接:[url]ht ...

  8. Python递归实现汉诺塔

    Python递归实现汉诺塔: def f3(n,x,y,z): if(n==1): print(x,'--->',z) else: f3(n-1,x,z,y) print(x,'--->' ...

  9. Python爬虫进阶四之PySpider的用法

    审时度势 PySpider 是一个我个人认为非常方便并且功能强大的爬虫框架,支持多线程爬取.JS动态解析,提供了可操作界面.出错重试.定时爬取等等的功能,使用非常人性化. 本篇内容通过跟我做一个好玩的 ...

随机推荐

  1. 封装jsonp

    1.写一个类封装jsonp: jsonp(url, params, success, funName)     参数url:请求地址     参数params:请求数据,可以是json对象,或形如&q ...

  2. getopt实现传参自动识别

    test.py #!/usr/bin/env python # -*- coding: utf-8 -*- import getopt import sys #-h-f-v为了下面的识别 opts,a ...

  3. vue嵌套路由--params传递参数

    在嵌套路由中,父路由向子路由传值除了query外,还有params,params传值有两种情况,一种是值在url中显示,另一种是值不显示在url中. 1.显示在url中index.html <d ...

  4. python-爬虫框架scrapy

    一 介绍 Scrapy一个开源和协作的框架,其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的,使用它可以以快速.简单.可扩展的方式从网站中提取所需的数据.但目前Scrapy的用途十分广泛,可 ...

  5. js动态检测加载 JQ

    var jqcdnurl = 'https://cdn.bootcss.com/jquery/3.2.1/jquery.js'; //控制台输出 function log() { for (var i ...

  6. mysqldump导出报错"mysqldump: Error 2013: Lost connection to MySQL server during query when dumping table `file_storage` at row: 29"

    今天mysql备份的crontab自动运行的时候,出现了报警,报警内容如下 mysqldump: Error 2013: Lost connection to MySQL server during ...

  7. 部署Linux项目

    部署Linux项目   1● 下载软件 ftp       安装 2● 创建连接 3● java项目   gunzip –c *.gz tar –xzf *.gz       rm –rf rm -r ...

  8. Mysql 用户ip访问根据省份查询

    表名:shop_interview_customer 表结构:customerId空为游客模式 interviedId customerId interviewIP iPdetail 1 1001 1 ...

  9. JavaScipt 中的事件循环(event loop),以及微任务 和宏任务的概念

    说事件循环(event loop)之前先要搞清楚几个问题. 1. js为什么是单线程的? 试想一下,如果js不是单线程的,同时有两个方法作用dom,一个删除,一个修改,那么这时候浏览器该听谁的?   ...

  10. DMA-总结

    概念DMA “Direct Memory Access(存储器直接访问).这是指一种高速的数据传输操作,允许在外部设备和存储器之间直接读写数据.整个数据传输操作在一个称为"DMA控制器&qu ...