python函数式编程之yield表达式形式
先来看一个例子
def foo():
print("starting...")
while True:
res = yield
print("res:",res)
g = foo()
next(g)
在上面的例子里,因为foo函数中有yield关键字,所以foo()函数的执行结果g是一个生成器,此时可以使用next(g)或者g.__next__()方法触发生成器的执行
程序的执行结果为
starting...
使用next(g)触发生成器的执行时,程序会按照正常的顺序从上向下执行,遇到yield,程序就会暂停
并把yield后面所接的值返回
打印next(g)的执行结果
def foo():
print("starting...")
while True:
res = yield
print("res:",res)
g = foo()
print(next(g))
程序执行结果
starting...
None
在上面的例子里,执行一次next(g)方法,程序暂停在yield那一行,此时再次调用next(g),程序会从yield语句那一行继续向下运行
修改上面的代码,多调用几次next方法,并打印next方法的返回结果
def foo():
print("starting...")
while True:
res = yield
print("res:",res)
g = foo()
print(next(g))
print("*"*20)
print(next(g))
上面这段代码的执行结果为
starting...
None
********************
res: None
None
可以看到,程序确实按猜想的步骤运行,但是上面的程序也有一个很明显的缺点:那就是上面的代码没有任何的实际意义:res的值永远为None
在实际的开发中,使用yield表达式形式的目的是yield可以得到一个值,然后yield把这个值赋值给某个变量,这样才有实际意义
那应该怎么操作才能为res变量赋一个值呢??那就是调用生成器自身的send方法
send方法可以触发一次生成器执行,同时还可以把send方法的参数传递给yield
修改上面的代码
def foo():
print("starting...")
while True:
res = yield
print("res:",res)
g = foo()
next(g)
print(g.send(5))
程序的执行结果为:
starting...
res: 5
None
来分析一下上面的代码的执行过程 :
1.程序开始执行以后,因为foo函数中有yield关键字,所以foo函数并不会真的执行,而是先得到一个生成器g.
2.直到调用next方法,foo函数正式开始执行,先执行foo函数中的print方法,然后进入while循环
3.程序遇到yield关键字,程序暂停,此时next(g)语句执行完成
4.程序执行g.send(5),程序会从yield关键字那一行继续向下运行,send会把5这个值传递给yield
5.yield接收到send方法传递过来的值,然后由yield赋值给res变量
6.由于send方法中包含next()方法,所以程序会继续向下运行执行print方法,然后再次进入while循环
7.程序执行再次遇到yield关键字,yield会返回后面的值,由于yield后面没有接任何参数,所以yield会返回None,程序再次暂停,直到再次调用next方法或send方法
修改代码,多次调用send方法
def foo():
print("starting...")
while True:
res = yield
print("res:",res)
g = foo()
next(g)
print(g.send(5))
print("*"*20)
print(g.send(10))
print("#"*20)
print(g.send(15))
执行程序,得到如下结果
starting...
res: 5
None
********************
res: 10
None
####################
res: 15
None
可以看到,上面代码的执行过程如同上面的分析的执行过程一样运行
在上面的例子里,如果调用send方法时,传递的参数为None,得到的结果会是怎么样的呢??
从上面的分析中,可以知道:
如果`g.send()`方法发送给yield关键字的参数为None,则yield关键字传递给res变量的值就为None
由于yield后面本来没有接任何值,所以yield返回的值默认也为None,所以程序执行结果会得到两个None
修改代码,验证上面的猜想
def foo():
print("starting...")
while True:
res = yield
print("res:",res)
g = foo()
next(g)
print("#"*20)
print(g.send(None))
查看程序的执行结果
starting...
####################
res: None
None
从程序的执行结果可以看出,如果调用生成器的send方法时,传递的参数为None,则程序执行的结果将会是两个None
使用yield表达式形式实现linux系统中的"grep -rl root /etc"命令
代码如下:
import os
def init(func):
def wrapper(*args, **kwargs):
g = func(*args, **kwargs)
next(g)
return g
return wrapper
@init
def get_file_path(target):
"""
get file abspath
# 阶段一:递归找文件的绝对路径,把文件的完事路径发送给阶段二
:param target:
:return:
"""
while True:
start_path = yield
g = os.walk(start_path)
for parent_dir, _, files in g:
for file in files:
file_path = r"%s\%s" % (parent_dir, file)
target.send(file_path)
@init
def opener(target):
"""
get file obj
# 阶段二:收到文件的完整路径,打开文件获取文件对象,把文件对象发送给阶段三
:param target:
:return:
"""
while True:
file_path = yield
with open(file_path, encoding='utf-8') as f:
target.send((file_path, f))
@init
def cat_file(target):
"""
read file content
# 阶段三:收到文件对象,for循环读取文件的每一行内容,把每一行内容发给阶段四
:param target:
:return:
"""
while True:
file_path, f = yield
for line in f:
file_content = target.send((file_path, line))
if file_content:
break
@init
def grep(target, pattern):
"""
grep function
# 阶段四:收到文件的一行内容,判断要查找的内容是否在这一行中,如果在,则把文件名发送给阶段五
:param target:
:param pattern:
:return:
"""
tag = False
while True:
file_path, line = yield tag
tag = False
if pattern in line:
target.send(file_path)
tag = True
@init
def printer():
"""
print file name
# 阶段五:收到文件名,打印结果
:return:
"""
while True:
filename = yield
print(filename)
path1 = "/root" # 定义要搜索的路径
path2 = "/etc" # 定义要搜索的路径
g = get_file_path(opener(cat_file(grep(printer(), "root"))))
print(g)
g.send(path1)
g.send(path2)
python函数式编程之yield表达式形式的更多相关文章
- Python函数式编程之lambda表达式
一:匿名函数的定义 lambda parameter_list: expression 二:三元表达式 条件为真时返回的结果 if 条件判断 else 条件为假的时候返回的结果 三:map map(f ...
- Python函数式编程之map()
Python函数式编程之map() Python中map().filter().reduce()这三个都是应用于序列的内置函数. 格式: map(func, seq1[, seq2,…]) 第一个参数 ...
- java函数式编程之lambda表达式
作为比较老牌的面向对象的编程语言java,在对函数式编程的支持上一直不温不火. 认为面向对象式编程就应该纯粹的面向对象,于是经常看到这样的写法:如果你想写一个方法,那么就必须把它放到一个类里面,然后n ...
- python 函数式编程之lambda( ), map( ), reduce( ), filter( )
lambda( ), map( ), reduce( ), filter( ) 1. lambda( )主要用于“行内函数”: f = lambda x : x + 2 #定义函数f(x)=x+2 g ...
- Python基础(9)_生成器(yield表达式形式)、面向过程编程
一.yield表达式形式 1 #装饰器,初始化含yield表达式的生成器 def init(func): def wrapper(*args,**kwargs): g=func(*args,**kwa ...
- Python 多进程编程之multiprocessing--Pool
Python 多进程编程之multiprocessing--Pool ----当需要创建的子进程数量不多的时候,可以直接利用multiprocessing 中的Process 动态生成多个进程, -- ...
- Python 多进程编程之multiprocessing--Process
Python 多进程编程之multiprocessing 1,Process 跨平台的进程创建模块(multiprocessing), 支持跨平台:windowx/linux 创建和启动 创 ...
- python并发编程之Queue线程、进程、协程通信(五)
单线程.多线程之间.进程之间.协程之间很多时候需要协同完成工作,这个时候它们需要进行通讯.或者说为了解耦,普遍采用Queue,生产消费模式. 系列文章 python并发编程之threading线程(一 ...
- python并发编程之gevent协程(四)
协程的含义就不再提,在py2和py3的早期版本中,python协程的主流实现方法是使用gevent模块.由于协程对于操作系统是无感知的,所以其切换需要程序员自己去完成. 系列文章 python并发编程 ...
随机推荐
- org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.coder520.mamabike.user.dao.UserMapper.selectByPrimaryKey
这个异常是IDEA中漏加载mapper.xml文件,在classes中没找到,所以要在配置文件中加入: !--如果不添加此节点mybatis的mapper.xml文件都会被漏掉.--> < ...
- ACL访问控制列表
acl是基于文件系统的,所以支不支持acl在于使用什么文件系统. FAT32文件系统不支持权限,也不区分大小写 如果一个分区不是安装系统时分的分区,是一个新的分区的话,默认是不支持acl CentOS ...
- SQL总结手册
1.SQL语法 (1)查询 SQL查询是使用最多的,需要凭借结构.索引和字段类型等因素.大多数据库含有一个优化器(optimizer),把用户查询转换为可选形式,以提高查询效率. 基本语法为: SEL ...
- 跨域问题jsonp
不得不说的同源政策: 同源策略,它是由Netscape提出的一个著名的安全策略.现在所有支持JavaScript 的浏览器都会使用这个策略.所谓同源是指域名,协议,端口相同.当一个浏览器的两个tab页 ...
- Android的微信智能心跳方案
原文地址: 年11月中旬时,因为基础组件组人手紧张,Leo安排我和春哥去广州轮岗支援.刚到广州的时候,Ray让我和春哥对Line和WhatsApp的心跳机制进行分析.我和春哥抓包测试了差不多两个多礼拜 ...
- PCIe设备的配置空间
关于PCI设备的配置空间网上已经有很多资料了,如下图就是PCI设备必须支持的64个字节的配置空间,范围为0x00-0x3f. 很多PCI设备仅仅支持者64字节的配置空间.PCI和PCIe配置空间的区别 ...
- 一句python,一句R︱模块导入与查看、数据读写出入、数据查看函数、数据类型、遍历文件
先学了R,最近刚刚上手python,所以想着将python和R结合起来互相对比来更好理解python.最好就是一句python,对应写一句R. pandas中有类似R中的read.table的功能,而 ...
- 用SPSS 画 人口金字塔(限SPSS 13.0以上)
现在网络上人口金字塔较多的是用excel来实现(可参考链接),但是用spss的步骤又很不明确,于是乎,想着自己试试. 在 SPSS 软件中,绘制人口金字塔是 SPSS13.0 新增的一种图形, 因此只 ...
- Procedure execution failed 2013 - Lost connection to MySQL server during query
1 错误描述 Procedure execution failed 2013 - Lost connection to MySQL server during query 2 错误原因 由错误描述可知 ...
- Unhandled event loop exception Java heap space
1 错误描述 2 错误原因 3 解决办法