1 协程函数 1.1 协程函数理解
> 协程函数就是使用了yield表达式形式的生成器
1
2
3
4
5
6
7
8
def eater (name) :
print("%s eat food" %name)
while True :
food = yield
print("done" )
g = eater("gangdan" )
print(g)
结果:generator object eater at 0x00000000028DC048 这里就证明了g现在就是生成器函数
1. 2 协程函数赋值过程 用的是yield的表达式形式
要先运行next() ,让函数初始化并停在yield,相当于初始化函数,然后再send() ,send会给yield传一个值 ** next()和send() 都是让函数在上次暂停的位置继续运行,
next是让函数初始化
send在触发下一次代码的执行时,会给yield赋值 **
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
def eater (name) :
print('%s start to eat food' %name)
food_list=[]
while True :
food=yield food_list
print('%s get %s ,to start eat' %(name,food))
food_list.append(food)
e=eater('钢蛋' )
print(next(e))
print(e.send('包子' ))
print(e.send('韭菜馅包子' ))
print(e.send('大蒜包子' ))
```
这里的关键是:
**要先运行next()函数**
用装饰器函数把next()函数先运行一次:
```python
def start (func) :
def wrapper (*args,**kwargs) :
res=func(*args,**kwargs)
next(res)
return res
return wrapper
@start # e = start(e)
def eater (name) :
print('%s start to eat food' %name)
food_list=[]
while True :
food=yield food_list
print('%s get %s ,to start eat' %(name,food))
food_list.append(food)
e=eater('钢蛋' )
print(e.send('包子' ))
print(e.send('韭菜馅包子' ))
print(e.send('大蒜包子' ))
在@start # e = start(e) 后面写上,运行start函数,start函数返回wrapper
1.3 协程函数使用装饰器初始化 这里主要是为了防止忘记初始化next操作,在装饰器中添加1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def init (func) :
def wrapper (*args,**kwargs) :
res = func(*args,**kwargs)
next(res)
return res
return wrapper
@init # eater=init(rater)
def eater (name) :
print("%s eat food" %name)
food_list=[]
while True :
food = yield food_list
print("%s star to eat %s" %(name,food))
food_list.append(food)
print("done" )
g = eater("gangdan" )
print(g.send("1" ))
print(g.send("2" ))
print(g.send("3" ))
print(g.send("4" ))
结果: gangdan eat food gangdan star to eat 1 [‘1’] gangdan star to eat 2 [‘1’, ‘2’] gangdan star to eat 3 [‘1’, ‘2’, ‘3’] gangdan star to eat 4 [‘1’, ‘2’, ‘3’, ‘4’]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
只要用到装饰器函数,马上写装饰器函数,写@init马上想到** eater=init(eater) **,先执行装饰器函数。
**关键是**next(res),这里是是对生成器进行初始化。这里就会只执行一次,执行完后后面运行的都是e.send()
### 1.2 协程函数的应用 ###
过滤一个文件下的子文件、字文件夹的内容中的相应的内容,在Linux中的命令就是 *grep -rl 'python' /etc*
使用了Python的包os 里面的walk(),能够把参数中的路径下的文件夹打开并返回一个元组
```python
>>> import os
>>> os.walk('D:\test')
generator object walk at 0x0000000002ADB3B8
>>> os.walk('D:\\test') # 以后使用这种路径方式,win下
>>> os.walk(r'D:\test') # 使用r 是让字符串中的符号没有特殊意义,针对的是转义
出现错误 ,是因为路径的原因,但是在不同的机器上有的是可以的1
2
3
4
5
>>> g=os.walk('D:\test' )
>>> next(g)
Traceback (most recent call last):
File "<stdin>" , line 1 , in <module>
StopIteration
以后推荐是用\
1
2
3
>>> g=os.walk('D:\\test' )
>>> next(g)
('D:\\test' , ['a' , 'b' ], ['test.txt' ])
返回的是一个元组 ,第一个元素 是文件的路径,第二个 是文件夹,第三个 是该路径下的文件
1.2.1 程序流程
找文件路径 –os.walk
然后打开文件 –open
读取文件的每一行内容 – for line in f
过滤一行内容中是否有Python if ‘python’ in line
打印包含Python的文件路径
程序是从上往下执行的,1产生的路径作为参数给2,2产生的给3…
上面产生的结果是下面的输入参数
1 找文件的路径 g是一个生成器,就能够用next()执行,每次next就是运行一次,这里的运行结果是依次打开文件的路径1
2
3
4
5
6
7
8
9
10
11
>>> g=os.walk('D:\\test' )
>>> next(g)
('D:\\test' , ['a' , 'b' ], ['test.txt' ])
>>> next(g)
('D:\\test\\a' , ['a1' ], ['a.txt' ])
>>> next(g)
('D:\\test\\a\\a1' , [], ['a1.txt' ])
>>> next(g)
('D:\\test\\b' , ['b1' ], ['b.txt' ])
>>> next(g)
('D:\\test\\b\\b1' , [], ['b1.txt' ])
我们在打开文件的时候需要找到文件的绝对路径,现在可以通过字符串拼接的方法把第一部分和第三部分进行拼接
用循环打开:1
2
3
4
5
import os
g = os.walk('D:\\test' )
for i in g:
print(i)
结果: (‘D:\test’, [‘a’, ‘b’], [‘test.txt’]) (‘D:\test\a’, [‘a1’], [‘a.txt’]) (‘D:\test\a\a1’, [], [‘a1.txt’]) (‘D:\test\b’, [‘b1’], [‘b.txt’]) (‘D:\test\b\b1’, [], [‘b1.txt’])
将查询出来的文件和路径进行拼接,拼接成绝对路径 1
2
3
4
5
6
7
8
import os
g = os.walk('D:\\test' )
for i in g:
for j in i[-1 ]:
file_path= '%s\\%s' %(i[0 ],j)
print(file_path)
结果: D:\test\test.txt D:\test\a\a.txt D:\test\a\a1\a1.txt D:\test\b\b.txt D:\test\b\b1\b1.txt
这样就把文件的所有的绝对路径 找出来了
用函数实现:1
2
3
4
5
6
7
8
9
10
11
12
def search () :
while True :
file_name = yield
g = os.walk(file_name)
for i in g:
for j in i[-1 ]:
file_path= '%s\\%s' %(i[0 ],j)
print(file_path)
g=search()
next(g)
g.send('D:\\test' )
2 然后打开文件 写程序中,在这里遇到的问题是 with open(file_path) as f: AttributeError: enter ,不明白是为什么,然后想到open可能是系统已经用了的,所以修改名字后执行成功。
1
2
3
4
5
6
7
@init # 初始化生成器
def opener (target) :
"打开文件,操作句柄"
while True :
file_path=yield
with open(file_path) as f:
target.send((file_path,f))
3 读取文件的每一行内容 1
2
3
4
5
6
@init
def cat (target) :
while True :
file_path,f=yield
for line in f:
target.send((file_path,line))
4 过滤一行内容中是否有 1
2
3
4
5
6
@init
def grep (pattern,target) :
while True :
file_path,line=yield
if pattern in line:
target.send(file_path)
5 打印包含Python的文件路径 1
2
3
4
5
@init
def printer () :
while True :
file_path=yield
print(file_path)
上面的是函数的定义阶段,下面是函数的执行阶段:
1
2
g=search(opener(cat(grep('python' ,printer()))))
g.send('D:\\test' )
target这个生成器: opener(cat(grep(‘python’,printer())))
对此的理解:
面向过程的编程思想 :流水线式的编程思想,在设计程序时,需要把整个流程设计出来
优点: 1:体系结构更加清晰 2:简化程序的复杂度
缺点: 1:可扩展性极其的差,所以说面向过程的应用场景是:不需要经常变化的软件,如:linux内核,httpd,git等软件