前言

  yield的英文单词意思是生产,刚接触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郑州妇科医院哪家好 yiyuan.120ask.com/zzfck/

  从程序的执行结果可以看出,如果调用生成器的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)

  前言

  yield的英文单词意思是生产,刚接触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郑州妇科医院哪家好 yiyuan.120ask.com/zzfck/

  从程序的执行结果可以看出,如果调用生成器的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)

  • 版权声明:文章来源于网络采集,版权归原创者所有,均已注明来源,如未注明可能来源未知,如有侵权请联系管理员删除。

发表回复

后才能评论