python-学习 协程函数 模块与包
一、协程函数
yield的用法:
1:把函数的执行结果封装好__iter__和__next__,即得到一个迭代器
2:与return功能类似,都可以返回值,但不同的是,return只能返回一次值,而yield可以返回多次值
3:函数暂停与再继续运行的状态是有yield保存
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # 例子1 2 # def chi(name): 3 # print('%s 开始上菜啦~'%name) 4 # cd=[] #菜单 5 # while True: 6 # food=yield cd 7 # cd.append(food) 8 # print('%s上了一份%s'%(name,food)) 9 # print(cd) 10 # esa=chi('alex') 11 # esa.send('芹菜') 12 # 例子2 13 # def chi(name): 14 # print('%s 开始上菜啦~'%name) 15 # cd=[] #菜单 16 # while True: 17 # food=yield cd 18 # cd.append(food) 19 # print('%s上了一份%s'%(name,food)) 20 # def shui(): 21 # name = input('服务员名字>>: ').strip() 22 # while True: 23 # food=input('菜名>>: ').strip() 24 # sc=chi(name) 25 # next(sc)#初始化:就是让函数执行停到yield 26 # if not food or not name :continue 27 # sc.send(food)#给yield传值 28 # shui()
通过装饰器初始化:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 def chushi(func): 2 def hua(*args,**kwargs): 3 g=func(*args,**kwargs) 4 next(g) 5 return g 6 return hua 7 @chushi 8 def chi(name): 9 print('%s 开始上菜啦~'%name) 10 cd=[] #菜单 11 while True: 12 food=yield cd 13 cd.append(food) 14 print('%s上了一份%s'%(name,food)) 15 print(cd) 16 esa=chi('alex') 17 esa.send('芹菜') 18 19 20 21 #例子2 22 # def chushi(func): 23 # def hua(*args,**kwargs): 24 # g=func(*args,**kwargs) 25 # next(g) 26 # return g 27 # return hua 28 # @chushi 29 # def chi(name): 30 # print('%s 开始上菜啦~'%name) 31 # cd=[] #菜单 32 # while True: 33 # food=yield cd 34 # cd.append(food) 35 # print('%s上了一份%s'%(name,food)) 36 # def shui(): 37 # name = input('服务员名字>>: ').strip() 38 # while True: 39 # food=input('菜名>>: ').strip() 40 # sc=chi(name) 41 # # next(sc)#初始化:就是让函数执行停到yield 42 # if not food or not name :continue 43 # sc.send(food)#给yield传值 44 # shui()
二、面向过程编程
面向过程:核心是过程二字,过程即解决问题的步骤,基于面向过程去设计程序就像是在设计
一条工业流水线,是一种机械式的思维方式
优点:程序结构清晰,可以把复杂的问题简单化,流程化
缺点:可扩展性差,一条流线只是用来解决一个问题
应用场景:linux内核,git,httpd,shell脚本
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 import os 2 def init(func): 3 def wrapper(*args,**kwargs): 4 g=func(*args,**kwargs) 5 next(g) 6 return g 7 return wrapper 8 9 #第一阶段:找到所有文件的绝对路径 10 @init 11 def search(target): 12 while True: 13 filepath=yield 14 g=os.walk(filepath) 15 for pardir,_,files in g: 16 for file in files: 17 abspath=r'%s\%s' %(pardir,file) 18 target.send(abspath) 19 # search(r'C:\Users\Administrator\PycharmProjects\python18期周末班\day5\aaa') 20 # g=search() 21 # g.send(r'C:\Python27') 22 23 #第二阶段:打开文件 24 @init 25 def opener(target): 26 while True: 27 abspath=yield 28 with open(abspath,'rb') as f: 29 target.send((abspath,f)) 30 31 32 33 34 #第三阶段:循环读出每一行内容 35 @init 36 def cat(target): 37 while True: 38 abspath,f=yield #(abspath,f) 39 for line in f: 40 res=target.send((abspath,line)) 41 if res:break 42 43 44 45 #第四阶段:过滤 46 @init 47 def grep(pattern,target): 48 tag=False 49 while True: 50 abspath,line=yield tag 51 tag=False 52 if pattern in line: 53 target.send(abspath) 54 tag=True 55 56 57 #第五阶段:打印该行属于的文件名 58 @init 59 def printer(): 60 while True: 61 abspath=yield 62 print(abspath) 63 64 g = search(opener(cat(grep('os'.encode('utf-8'), printer())))) 65 # g.send(r'C:\Users\Administrator\PycharmProjects\python18期周末班\day5\aaa') 66 67 g.send(r'C:\Users\Administrator\PycharmProjects\python18期周末班') 68 #a1.txt,a2.txt,b1.txt
三、递归与二分法
递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #直接 2 # def func(): 3 # print('from func') 4 # func() 5 # 6 # func() 7 8 #间接 9 # def foo(): 10 # print('from foo') 11 # bar() 12 # 13 # def bar(): 14 # print('from bar') 15 # foo() 16 # 17 # foo()
递归的执行分为两个阶段:
1 递推
2 回溯
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 l =[1, 2, [3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15,[16,[17,]],19]]]]]]] 2 3 def search(l): 4 for item in l: 5 if type(item) is list: 6 search(item) 7 else: 8 print(item) 9 10 search(l)
二分法
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #例子1 2 l = [1,2,5,7,10,31,44,47,56,99,102,130,240] 3 4 5 def binary_search(l,num): 6 print(l) [10, 31] 7 if len(l) > 1: 8 mid_index=len(l)//2 1 9 if num > l[mid_index]: 10 in the right 11 l=l[mid_index:] l=[31] 12 binary_search(l,num) 13 elif num < l[mid_index]: 14 in the left 15 l=l[:mid_index] 16 binary_search(l,num) 17 else: 18 print('find it') 19 else: 20 if l[0] == num: 21 print('find it') 22 else: 23 print('not exist') 24 return 25 26 binary_search(l,32) 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #例子2 45 l = [1,2,5,7,10,31,44,47,56,99,102,130,240] 46 47 48 def binary_search(l,num): 49 print(l) 50 if len(l) == 1: 51 if l[0] == num: 52 print('find it') 53 else: 54 print('not exists') 55 return 56 mid_index=len(l)//2 57 mid_value=l[mid_index] 58 if num == mid_value: 59 print('find it') 60 return 61 if num > mid_value: 62 l=l[mid_index:] 63 if num < mid_value: 64 l=l[:mid_index] 65 binary_search(l,num) 66 67 binary_search(l,32)
四、模块与包
1.模块只在第一次导入时才会执行,之后的导入都是直接引用内存已经存在的结果
模块搜索路径:
内存中--》内置模块————》sys.path
注意:自定义的模块名一定不要与python自带的模块名重名
2.什么是模块
常见的场景:一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
但其实import加载的模块分为四个通用类别:
1 使用python编写的代码(.py文件)
2 已被编译为共享库或DLL的C或C++扩展
3 包好一组模块的包
4 使用C编写并链接到python解释器的内置模块
3.import的导入
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #spam.py 2 print('from the spam.py') 3 4 money=1000 5 6 def read1(): 7 print('spam->read1->money',money) 8 9 def read2(): 10 print('spam->read2 calling read') 11 read1() 12 13 def change(): 14 global money 15 money=0
导入span模块
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #test.py 2 import spam #只在第一次导入时才执行spam.py内代码,此处的显式效果是只打印一次'from the spam.py',当然其他的顶级代码也都被执行了,只不过没有显示效果. 3 import spam 4 import spam 5 import spam 6 ''' 7 执行结果: 8 from the spam.py 9 '''
可以使用__all__来控制*(用来发布新版本)
在spam.py中新增一行
__all__=['money','read1'] #这样在另外一个文件中用from spam import *就这能导入列表中规定的两个名字
4.rom.......import的导入
优点:使用源文件内的名字时无需加前缀,使用方便
缺点:容易与当前文件的名称空间内的名字混淆
5.绝对导入和相对导入
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 在glance/api/version.py 2 3 #绝对导入 4 from glance.cmd import manage 5 manage.main() 6 7 #相对导入 8 from ..cmd import manage 9 manage.main()
1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法
2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录)
3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件
强调:
1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错
2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块