首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

成为Python大牛必须要掌握的高端语法——yield

作者:grisse链接:

https://segmentfault.com/a/1190000017405045

https://stackoverflow.com/questions/231767/what-does-the-yield-keyword-do

问题

Python中关键字的用途是什么?它有什么作用?

例如,我试图理解以下代码:

这是调用者(caller):

当调用方法时会发生什么?返回了一个列表(list)?还是返回了一个元素?然后被重复调用了吗?调用何时结束?

代码来自 Jochen Schulz (jrschulz), who made a great Python library for metric spaces.

回答

要想理解的作用,你必须了解什么是生成器(generators),在这之前,我们先来看可迭代对象(iterables)。

可迭代对象 (iterables)

当你创建了一个列表,你可以遍历这个列表读取它的每一个元素,逐个读取列表元素称为迭代(iteration)。

就是一个可迭代对象(iterable)。当你使用列表生成式(list comprehension)创建一个列表(list),即创建了一个可迭代对象。

可以使用的所有对象都是可迭代对象:列表(lists)、字符串、文件...

这些可迭代对象使用很方便,因为你可以根据需要如你所愿的读取其中的元素。但是,当你有大量数据时把所有值都存储在内存中,这样往往不是你想要的( but you store all the values in memory and this is not always what you want when you have a lot of values.)。

生成器 (Generators)

生成器是迭代器(iterators),但是只能迭代一次,生成器不会将所有值存储在内存中,而是实时的生成这些值:

看上去除了用替换了原来的外,它们没什么不同。但是,你不可以再次使用,因为生成器只能被迭代一次:计算出0,然后并不保存结果和状态继续计算出1,最后计算出4,逐一生成。

yield

是一个类似 的关键字,不同的是这个函数将返回一个生成器。

这个例子没有什么实际作用。但是当你知道你的函数将返回大量你只需要读取一次的值时,使用生成器是一个有效的做法。

要掌握 ,你必须要知道当你调用这个函数时,你在函数体中编写的代码并没有立马执行

该函数仅仅返回一个生成器对象,这有点棘手 :-)

然后,你的代码将从循环每次使用生成器停止的位置继续执行。

现在到了关键部分:

第一次调用从函数创建的生成器对象,函数将从头开始执行直到遇到,然后返回后的值作为第一次迭代的返回值。接下来每次调用都会再次执行你在函数中定义的循环,并返回(return)下一个值,直到没有值可以返回(return)。

当循环结束,或者不满足条件,导致函数运行但不会执行(not hit),此时生成器被认为是空的。

问题代码的解释 (Your code explained)

生成器 (Generator):

调用者 (Caller):

这段代码包含几个高明的部分:

这个循环对列表进行迭代,但是迭代中列表还在不断扩展 :-) 这是一种遍历嵌套数据的简明方法,即使这样有些危险,因为你可能会陷入死循环中。在这个例子中,穷尽了生成器产生的所有值,但不断的创建新的生成器对象加入到列表,因为每个对象作用在不同节点上,所以每个生成器都将生成不同的值。

是一个列表(list)对象的方法,作用于可迭代对象(iterable),并将其值添加到列表里。

通常,通常我们将列表作为参数传递给它:

但是在你的代码里它接收到的是一个生成器(generator),这很好,因为:

你不必重复读取这些值

你可以有很多子对象,但不需要将它们都存储在内存里。

它很有效,因为Python不关心一个方法的参数是否是列表,Python只希望他是一个可迭代对象,所以这个参数可以是列表,元组,字符串和生成器!这就是所谓的,这也是Python为何如此酷的原因之一,但这已经是另外一个问题了......

你可以在这里停下,来看一些生成器的高级用法:

控制生成器的穷尽 (Controlling a generator exhaustion)

注意,对于Python 3,请使用 或者

这在很多场景都非常有用,例如控制资源的获取。

Itertools,你最好的朋友 (Itertools, your best friend)

itertools模块包含很多处理可迭代对象的特殊方法。曾经想要复制一个生成器吗?连接两个生成器?用一行代码将嵌套列表中的值进行分组?不创建另一个列表进行?

只需要

需要一个例子?让我们来看看4匹马赛跑到达终点先后顺序的所有可能情况:

了解迭代的内部机制 (Understanding the inner mechanisms of iteration)

迭代是一个实现可迭代对象(实现的是 __iter__() 方法)和迭代器(实现的是 __next__() 方法)的过程。你可以获取一个迭代器的任何对象都是可迭代对象,迭代器可以让你迭代遍历一个可迭代对象(Iterators are objects that let you iterate on iterables.) .

在这篇文章中有关于循环如何工作的更多信息:

http://effbot.org/zone/python-for-statement.htm

(完)

看完本文有收获?请转发分享给更多人

关注「Python那些事」,做全栈开发工程师

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181231B08A4100?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券