表达式形式的yield
yield的语句形式: yield 1
yield的表达式形式: x=yield
1 x=yield 2 g.send(‘1111‘) #先把1111传给yield,由yield赋值给x,然后再往下执行,直到再次碰到yield,然后把yield后的返回值返回
协程函数示例
1 def gen(func): 2 def wrapper(*args,**kwargs): 3 res = func(*args,**kwargs) 4 next(res) #相当于next(g)或者g.send(None) 5 return res 6 return wrapper 7 8 @gen 9 def eater(name): 10 print(‘%s start to eat‘ % name) 11 food_list = [] 12 while True: 13 food = yield food_list| 14 food_list.append(food) 15 print(‘%s start to eat %s‘% (name,food)) 16 17 g = eater(‘Albert‘) #初始化操作,由装饰函数gen对eater函数进行初始化,传入一个空值 18 print(g.send(‘Apple‘)) #此时函数挂起在红线出,send执行后,将Apple传给yield,并有yield赋值给food,之后再执行append操作,让后返回food_list 19 print(g.send(‘Peach‘))
模拟 grep -rl ‘python‘ /root 示例
1 import os 2 3 def init(func): 4 def wrapper(*args,**kwargs): 5 res = func(*args,**kwargs) 6 next(res) 7 return res 8 return wrapper 9 10 @init 11 def search_dir(target): 12 while True: 13 search_path = yield #将搜索路径赋值给search_path 14 g = os.walk(search_path)#遍历目录下的所有文件夹和子文件夹以及各文件夹下面的文件 15 for par_dir, _, files in g: #遍历列表g中所有的父级文件夹目录和文件 16 for file in files:#遍历文件夹下所有文件 17 file_abs_path = r‘%s\%s‘, (par_dir, file)#形成绝对路径字符串 18 target.send(file_abs_path)#将文件绝对路径传值给open_file函数 19 @init 20 def open_file(target): 21 while True: 22 file_abs_path = yield #将文件绝对路径赋值给file_abs_path 23 with open(file_abs_path,‘r‘, encoding=‘urf-8‘) as f: 24 target.send((f,file_abs_path))#将文件内容和绝对路径传值给cat_file函数 25 @init 26 def cat_file(target): 27 while True: 28 f, file_abs_path = yield #将yield中文件内容和绝对路径赋值 29 for line in f:#逐行遍历文件内容 30 tag = target.send(line, file_abs_path)#将每行内容和绝对路径传值给grep_line函数进行判断,并返回值tag 31 if tag: #如果返回值tag为True,就停止对该文件剩余行数的遍历,并进行下一文件逐行遍历 32 break 33 34 @init 35 def grep_line(target,pattern): 36 tag = False 37 while True: 38 line, file_abs_path = yield tag #将每行内容和绝对路径赋值,并取到返回值tag 39 tag = False #初始化tag 40 if pattern in line:#如果改行内容匹配到目标字符串,返回值tag为True 41 tag = True 42 target.send(file_abs_path) #将文件绝对路径传值给print函数打印 43 @init 44 def print_file(): 45 file_abs_path = yield 46 print(file_abs_path) 47 48 x = r‘C:\Users\Administrator\PycharmProjects\python17期\day5\a‘ 49 g = search_dir(open_file(cat_file(grep_line(print_file(), ‘python‘)))) 50 print(g) 51 g.send(x)
面向过程的程序设计:是一种流水线式的编程思路,是机械式
优点:
程序的结构清晰,可以把复杂的问题简单
缺点:
扩展性差
应用场景:
linux内核,git,httpd
匿名函数
匿名函数:用之则弃的函数,基本不会占用内存,不像正常的全局函数,会存活到程序结束
1 def func(x,y): 2 return x+y 3 func(1,2) 4 5 f=lambda x,y:x+y 6 print(f) 7 print(f(1,2))
内置函数补充
1. max,min,zip,sorted的用法, 运用到匿名函数的概念
1 salaries={ 2 ‘egon‘:3000, 3 ‘alex‘:100000000, 4 ‘wupeiqi‘:10000, 5 ‘yuanhao‘:2000 6 } 7 for i in salaries: 8 print(i) 9 print(max(salaries)) 10 res=zip(salaries.values(),salaries.keys()) 11 12 print(list(res)) 13 print(max(res)) 14 15 def func(k): 16 return salaries[k] 17 18 print(max(salaries,key=func)) 19 print(max(salaries,key=lambda k:salaries[k])) 20 print(min(salaries,key=lambda k:salaries[k])) 21 22 print(sorted(salaries)) #默认的排序结果是从小到到 23 print(sorted(salaries,key=lambda x:salaries[x])) #默认的排序结果是从小到到 24 print(sorted(salaries,key=lambda x:salaries[x],reverse=True)) #默认的排序结果是从小到到
2. map,reduce,filter函数
1 l=[‘alex‘,‘wupeiqi‘,‘yuanhao‘] 2 res=map(lambda x:x+‘_SB‘,l) 3 print(res) 4 print(list(res)) 5 6 nums=(2,4,9,10) 7 res1=map(lambda x:x**2,nums) 8 print(list(res1)) 9 10 from functools import reduce 11 l=[1,2,3,4,5] 12 print(reduce(lambda x,y:x+y,l,10)) 13 14 l=[‘alex_SB‘,‘wupeiqi_SB‘,‘yuanhao_SB‘,‘egon‘] 15 res=filter(lambda x:x.endswith(‘SB‘),l) 16 print(list(res))
递归调用
1. 定义:在函数调用过程中,直接或间接地调用了函数本身,这就是函数的递归调用
2. 递归效率低,需要在进入下一次递归时保留当前的状态,解决方法是尾递归,但是Python没有,且对递归层级做了限制
1.必须有一个明确的结束条件
2.每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3.递归效率不高,递归层次过多会导致栈溢出。
1 import sys 2 print(sys.getrecursionlimit()) #查看Python可以递归的层数,默认1000,可设置 3 print(sys.setrecursionlimit(1000000)) #设置Pyth可递归层数。最高8000 4 print(sys.getrecursionlimit()) #查看设置结果
3. 递归的原理
1 age(5)=age(4)+2 2 age(4)=age(3)+2 3 age(3)=age(2)+2 4 age(2)=age(1)+2 5 age(1)=18 6 7 age(n)=age(n-1)+2 #n>2 8 age(n)=18 #n=1 9 10 def age(n): 11 if n == 1: 12 return 18 13 return age(n-1)+2 14 print(age(5))
4. 递归的应用(二分法)
1 第一种方式: 2 raw_lst = [1,5,324,12,67,34,32,879,65,23,4,78,56,2,6,8] 3 while True: 4 lst = sorted(raw_lst) 5 t_num = input(‘>>>: ‘) 6 n = int(t_num) 7 while True: 8 if len(lst) // 2 == 0: 9 print(‘Nothing found‘) 10 break 11 elif lst[len(lst) // 2] == n: 12 print(‘Bingo‘) 13 break 14 elif lst[len(lst) // 2] > n: 15 lst = lst[:len(lst) // 2] 16 elif lst[len(lst) // 2] < n: 17 lst = lst[len(lst) // 2:] 18 19 第二种方式: 20 raw_list = [1, 2, 10,33,53,71,73,75,77,85,101,201,202,999,11111] 21 def search_num(target_num, seq): 22 seq = sorted(seq) # 如果列表是无序的情况下需要先进性排序 23 if len(seq) == 0: 24 return ‘Not found...‘ 25 mid_index = len(seq)//2 26 mid_num = seq[mid_index] 27 if mid_num > target_num: 28 seq = seq[:mid_index] 29 search_num(target_num, seq) 30 elif mid_num < target_num: 31 seq = seq[mid_index+1:] 32 search_num(target_num, seq) 33 elif mid_num == target_num: 34 print(‘Bingo!!!‘) 35 search_num(33,raw_list)
模块
1. 什么是模块
一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀
2. 为什么要使用模块
程序中定义的函数或者变量都会因为python解释器的关闭而丢失,因此通常我们会将程序以文件的方式保存下来方便重复利用。
为了方便管理越来越多的文件,我们将这些文件归纳为模块,实用的时候就把模块导入到程序中
3. 如何使用模块
1 # spam模块文件 2 # -*- coding:utf-8 -*- 3 # !/usr/bin/python 4 __all__ = [‘money‘,‘read1‘] #from spam import * 导入的所有变量,类表中只添加所需变量 5 money = 1000 6 def read1(): 7 print(‘spam->read1->money‘,money) 8 def read2(): 9 print(‘spam->read2 calling read1‘) 10 read1() 11 def change(): 12 global money 13 money = 0 14 #spam.py当作脚本执行时,__name__==‘__main__‘ 15 #spam.py当作模块导入时,__name__==‘模块名‘ 16 # print(‘当前文件的用途是:‘, __name__) 17 #作用:用于判断当前文件时按照脚本执行还是模块执行 18 if __name__ == ‘__main__‘: 19 print(‘from the spam.py‘) 20 print(‘当作脚本执行‘) 21 change() 22 print(money)
1 import...导入模块进行的操作: 2 1. 产生新的名称空间 3 2. 以新建的名称空间为全局名称空间,执行文件的代码 4 3. 拿到一个模块名spam,指向spam.py产生的名称空间 5 6 # fortest.py文件 7 # -*- coding:utf-8 -*- 8 # !/usr/bin/python 9 import spam as x #起一个别名作为引用 10 import spam 11 money = 2000 #此money并非spam名称空间中的money 12 print(spam.money) #从spam的名称空间中的money变量值 13 print(x.money) #相同效果 14 spam.read1() 15 spam.read2() 16 spam.change() #修改spam空间中的money变量,任然以spam名称空间定义的为准 17 print(spam.money) 18 19 from...import...导入模块进行的操作: 20 1. 产生新的名称空间 21 2. 以新建的名称空间为全局名称空间,执行文件的代码 22 3. 直接拿到就是spam.py产生的名称空间的名字 23 24 优点:方便,不用加前缀 25 缺点: 容易跟当前文件的名称空间冲突 26 27 from spam import * #将spam中所有内容导入,使用时不用加前缀,慎用,容易和当前名称空间中变量发生冲突 28 可以在模块文件中使用__all__=[]的方法来加以控制所需导入的名称 29 30 # fortest.py文件 31 # -*- coding:utf-8 -*- 32 # !/usr/bin/python 33 from spam import read1,money,read2,change 34 print(money) 35 read1() 36 money = 10 #从spam取到的money的值已经被重新绑定赋值,但是spam中的money值没有改变 37 print(money) 38 def read1(): 39 print(‘===> from fortest.py read1‘) 40 read1() #使用当前名称空间中函数定义的功能 41 read2() #与导入方式无关,此函数从哪个名称空间导入,就会任然沿用该空间函数功能,所以调用的仍然是spam中的read1函数
模块搜索路径
顺序:内存空间 -> 内置函数 -> sys.path(从当前路径开始查找)
import sys
print(sys.path) #查看系统路径
如果需要添加的模块和当前文件不在同一个目录中,那么需要将模块的路径添加到sys.path中,才能添加成功
或者将该模块文件添加到site-package文件夹中
re模块
re.match:尝试从字符串的开始匹配一个模式,如:下面的例子匹配第一个单词。
re.match的函数原型为:re.match(pattern, string, flags)
第一个参数是正则表达式,这里为"(\w+)\s",如果匹配成功,则返回一个Match,否则返回一个None;
第二个参数表示要匹配的字符串;
第三个参数是标致位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
1 import re 2 text = "JGood is a handsome boy, he is cool, clever, and so on..." 3 m = re.match(r"(\w+)\s", text) 4 if m: 5 print m.group(0), ‘\n‘, m.group(1) 6 else: 7 print ‘not match‘
re.search:会在字符串内查找模式匹配,只到找到第一个匹配然后返回,如果字符串没有匹配,则返回None。
re.search的函数原型为: re.search(pattern, string, flags)
每个参数的含意与re.match一样。
re.match与re.search的区别:re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
1 import re 2 text = "JGood is a handsome boy, he is cool, clever, and so on..." 3 m = re.search(r‘\shan(ds)ome\s‘, text) 4 if m: 5 print m.group(0), m.group(1) 6 else: 7 print ‘not search‘
re.sub: 用于替换字符串中的匹配项。下面一个例子将字符串中的空格 ‘ ‘ 替换成 ‘-‘ :
re.sub的函数原型为:re.sub(pattern, repl, string, count)
其中第二个函数是替换后的字符串;本例中为‘-‘
第四个参数指替换个数。默认为0,表示每个匹配项都替换。
re.sub还允许使用函数对匹配项的替换进行复杂的处理。如:re.sub(r‘\s‘, lambda m: ‘[‘ + m.group(0) + ‘]‘, text, 0);将字符串中的空格‘ ‘替换为‘[ ]‘。
1 import re 2 text = "JGood is a handsome boy, he is cool, clever, and so on..." 3 print re.sub(r‘\s+‘, ‘-‘, text)
re.split: 可以使用re.split来分割字符串,如:re.split(r‘\s+‘, text);将字符串按空格分割成一个单词列表。
re.findall: 可以获取字符串中所有匹配的字符串。如:re.findall(r‘\w*oo\w*‘, text);获取字符串中,包含‘oo‘的所有单词。
re.compile: 把正则表达式编译成一个正则表达式对象。可以把那些经常使用的正则表达式编译成正则表达式对象,这样可提高一定的效率。下面是一个正则表达式对象的一个例子:
1 import re 2 text = "JGood is a handsome boy, he is cool, clever, and so on..." 3 regex = re.compile(r‘\w*oo\w*‘) 4 print regex.findall(text) #查找所有包含‘oo‘的单词 5 print regex.sub(lambda m: ‘[‘ + m.group(0) + ‘]‘, text) #将字符串中含有‘oo‘的单词用[]括起来。
包
从目录级别来组织模块的,也是通过import引入
1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法。
2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
3. import导入文件时,产生名称空间中的名字来源于文件,import包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
注意事项:
1. 关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:
凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。
2. 对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。
3. .对比import item 和from item import name的应用场景:如果我们想直接使用name那必须使用后者。