Discuss / Python / 关于 yield, yield from

关于 yield, yield from

Topic source

7hana7os

#1 Created at ... [Delete] [Delete and Lock User]

关于 yield

yield一词的意思有 n.产出,产量;v.让步,提供。 所以当我们定义一个生成器函数时(带yield关键字的函数):

  def Iter():
    for i in range(10):
        yield i

这个Iter()函数的工作就是按顺序产出(生成)0~910个数字,同时,它也是一个可迭代对象。 而要产出0~9,则需通过next()函数不断调用方可,同时我们也知道,python的for循环本质就是不断调用next()函数从可迭代对象里取值。因此,若我们要输出0~9,只需:

  for val in Iter():
      print(val)

得到如下输出:

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9

关于 yield from

从字面意思上来说yield from就是 从...中生成,而实质上它的确如此。 那么问题来了,它可以从那里yield呢? 我们看回上面的:

    def Iter():
    for i in range(10):
        yield i

这里的irange(10)里的元素,而range(10)是一个可迭代对象(这点很重要!!!)。所以我们不妨大胆假设:yield from就是 从<可迭代对象>中生成。 那么我们试着改写一下上面的Iter()

  def Iter():
      yield from range(10)

再执行如下代码:

  for val in Iter():
      print(val)

意料之中,我们得到如下输出:

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9

综上,yield from=for i in <可迭代对象>: yield i

我们可以再进一步。我们知道,可迭代对象有许多,列表、元组、字典、列表生成式,甚至生成器或生成器函数本身都是一个可迭代对象。那么我们是否可以定义一个生成器函数,然后yield from它呢? 答案是肯定的:

  #定义一个生成器函数
  def Iter():
    for i in range(10):
        yield i

  #定义一个 "yield from生成器函数" 的生成器函数
  def yieldFromIter():
    yield from Iter()

  #封装print
  def out():
    for i in yieldFromIter():
        print(i)

  f __name__ == '__main__':
      out()

执行上面脚本,我们同样能得到如下输出:

  0
  1
  2
  3
  4
  5
  6
  7
  8
  9

以上就是本人对yieldyield from的一些简单解释。如有不明,欢迎各位与我探讨。

廖雪峰

#2 Created at ... [Delete] [Delete and Lock User]

把yield from理解为“递归调用Iterable并yield”

>>> def yf():
...     yield from range(1, 5)
...     yield from range(10, 15)
... 
>>> for x in yf():
...     print(x)
... 
1
2
3
4
10
11
12
13
14

翻译成yield就是:

def yf():
    for x in range(1, 5):
        yield x
    for x in range(10, 15):
        yield x

关键是这玩意还可以“递归”:

def yf2():
    yield from yf()
    # 效果等同:
    # for x in yf():
    #     yield x

所以yield from是一个“代理”


  • 1

Reply