写在前面
凭着爱,再回首;
一、协程函数(生成器:yield的表达式形式)
1.yield 的语句形式: yield 1
- 这种方式在 Python基础(函数部分)-day04 里面详细介绍过,这里不再赘述;
2.yield 的表达式形式: x=yield
- 示例1:使用 next() 方法调用生成器执行,没有给yield传值;
1 defdeco(func): # 定义了一个装饰器2 def wrapper(*args,**kwargs):3 res = func(*args,**kwargs)4 next(res) # 就是为了先执行一下 next方法5 returnres6 returnwrapper7
8 @deco9 defeater(name):10 print('%s ready to eat' %name)11 whileTrue:12 food=yield
13 print("%s start to eat %s" %(name, food))14 g = eater('alex') # 得到一个生成器函数15 next(g) # 第一次调用 生成器的next方法;(装饰器里提前执行了一次 next方法)16 next(g) # 第二次调用...17
18 ---
19 alex ready to eat # 装饰器里调用 next() 的打印结果20 alex start to eat None # 第一次调用 next() 的打印结果21 alex start to eat None # 第二次调用...
- 示例2:使用 send() 方法调用生成器执行,并给yield传值;
1 defdeco(func):2 def wrapper(*args,**kwargs):3 res = func(*args,**kwargs)4 next(res)5 returnres6 returnwrapper7
8 @deco9 defeater(name):10 print('%s ready to eat' %name)11 food_list =[]12 whileTrue:13 food=yield
14 food_list.append(food)15 print("%s start to eat %s" %(name, food))16 print("%s have eaten: %s" %(name,food_list))17 g = eater('alex')18 g.send('tomato') # 第一次调用生成器执行,传入 'tomato' 给 yield,然后由yield赋值给food变量;然后向下执行进入下一次while循环,暂停并等待;19 g.send('potato')20 g.send('beef')21 g.send('rice')22
23 ---
24 alex ready to eat25 alex start to eat tomato26 alex have eaten: ['tomato']27 alex start to eat potato28 alex have eaten: ['tomato', 'potato']29 alex start to eat beef30 alex have eaten: ['tomato', 'potato', 'beef']31 alex start to eat rice32 alex have eaten: ['tomato', 'potato', 'beef', 'rice']
注意:next(g) #等同于 g.send(None);
3.yield表达式形式的应用
1 #!/usr/bin/python
2 #-*- coding:utf-8 -*-
3
4 #实现Linux下的如下命令: grep -rl 'python' path
5 #即给出一个目录和patten,递归遍历查找该目录下含有该patten的文件完整路径,如果文件含有多行则需要去重;
6
7 importos8
9 definit(func): # 定义一个执行 next() 功能的装饰器;10 def wrapper(*args,**kwargs):11 res = func(*args,**kwargs)12 next(res)13 returnres14 returnwrapper15 @init16 defsearch_all_file(target):17 whileTrue:18 path = yield # 利用send()给yield传值,然后赋值给path
19 g =os.walk(path) # 根据给定path,遍历该目录下所有文件,也包含所有子目录下的文件;20 for path,_,files ing:21 for file infiles:22 target.send(r'%s\%s' %(path,file)) # 利用send()把遍历得到的所有文件传递给下一个生成器的yield;不接受yield的返回值;23 @init24 defopener(target):25 whileTrue:26 file_to_open = yield # 接收调用者传递的文件名,即 search_all_file()函数里send()的参数;
27 with open(file_to_open,encoding='utf-8') as rf:28 for line inrf: # 打开文件,遍历该文件内容;29 res =target.send((file_to_open,line)) # 利用send()把该文件名和每次遍历的每行内容传递给下一个生成器的yield;并用res接收返回值;30 ifres: # 需要注意的一点:send()参数只能是一个值,多个参数则可以以元组的形式传递;31 break
32 @init33 defgrep(patten):34 flag =False # 定义一个标识位35 whileTrue:36 the_file,line = yieldflag # 接收调用者传递的文件名和该文件名下遍历得到的每行内容;37 flag =False38 if patten inline:39 flag =True # 如果某个文件某行内容包含 patten 关键字,则将标识位置为 True,并再下一次调用的时候返回给调用者;40 print(the_file) # 打印匹配到的文件名;41
42 path = r'D:\soft\work\Python_17\day05\a' # path=r'path' --> r'xxx' 表示绝对 row data,表示不用转意;
43 g = search_all_file(opener(grep('python'))) # 注意这里的调用写法!!!44 print(g)45 g.send(path)
二、递归调用
1.递归的概念
在函数调用过程中,直接或间接地调用了函数本身,这就是函数的递归调用;
包括两部分:递推和回溯;
1 deff1():2 print('from f1')3 f1()4
5 f1()
2.Python3中递归的层数限制
1 importsys2 print(sys.getrecursionlimit()) # 查看默认递归次数上限3 sys.setrecursionlimit(2000) # 认为设置递归上限4 print(sys.getrecursionlimit())5
6 ---
7 1000
8 2000
3.递归特性
1. 必须有一个明确的结束条件;
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少;
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧;每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出);
4.堆栈扫盲:http://www.cnblogs.com/lln7777/archive/2012/03/14/2396164.html
5.尾递归优化:http://egon09.blog.51cto.com/9161406/1842475
4.递归具体应用
1.二分法查找某个元素
前提:输入的可循环对象必须是有序的;
1 num_list = [1, 3, 6, 7, 9, 12, 14, 16, 17, 18, 20, 21, 22, 23, 30, 32, 33, 35,99]2
3 deffind_num(num_list, number):4 if 0 ==len(num_list):5 print('No exist.')6 return
7 mid_index = len(num_list)//2
8 mid_value =num_list[mid_index]9 if number >mid_value:10 num_list = num_list[mid_index+1:]11 find_num(num_list,number)12 elif number