Python中`yield`关键字有什么用?

Python中yield关键字有什么用? 它能做什么?

例如,我试图理解这段代码1:

def _get_child_candidates(self, distance, min_dist, max_dist):
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild

回答

要了解yield的作用,您必须了解生成器是什么。 在了解生成器之前,您必须了解iterables。

迭代器
创建列表时,您可以逐个读取其项目。 逐个读取其项称为迭代:

mylist = [1, 2, 3]
for i in mylist:
... print(i)
1
2
3
mylist是一个可迭代的。 当您使用列表理解时,您创建了一个列表,因此一个可迭代的:

mylist = [x*x for x in range(3)]
for i in mylist:
... print(i)
0
1
4
您可以使用"for... in..."的所有内容都是可迭代的;lists,strings,文件。..

这些iterables很方便,因为您可以随心所欲地读取它们,但是您将所有值存储在内存中,当您有很多值时,这并不总是您想要的。

发电机
生成器是迭代器,一种可迭代的你只能迭代一次。 生成器不会将所有值存储在内存中,它们会动态生成值:

mygenerator = (x*x for x in range(3))
for i in mygenerator:
... print(i)
0
1
4
除了你使用()而不是[]之外,它是一样的。 但是,您不能第二次执行for i in mygenerator,因为生成器只能使用一次:它们计算0,然后忘记它并计算1,并结束计算4,一个接一个。

产量
yield是一个像return一样使用的关键字,除了函数将返回一个生成器。

def create_generator():
... mylist = range(3)
... for i in mylist:
... yield i*i
...
mygenerator = create_generator() # create a generator
print(mygenerator) # mygenerator is an object!
<generator object create_generator at 0xb7555c34>
for i in mygenerator:
... print(i)
0
1
4
这里是一个无用的例子,但是当你知道你的函数将返回一组巨大的值时,它很方便,你只需要读取一次。

要掌握yield,您必须了解当您调用函数时,您在函数体中编写的代码不会运行。函数只返回生成器对象,这有点棘手。

然后,您的代码将从每次for使用生成器时停止的位置继续。

现在最难的部分:

当for第一次调用从你的函数创建的生成器对象时,它将从一开始就在你的函数中运行代码,直到它点击yield,然后它将返回循环的第一个值。 然后,每个后续调用都将运行您在函数中编写的循环的另一个迭代,并返回下一个值。 这将继续下去,直到生成器被认为是空的,这发生在函数运行而没有击中yield时。 这可能是因为循环已经结束,或者因为你不再满足an"if/else"。

你的代码解释
发生器:

Here you create the method of the node object that will return the generator

def _get_child_candidates(self, distance, min_dist, max_dist):

# Here is the code that will be called each time you use the generator object:

# If there is still a child of the node object on its left
# AND if the distance is ok, return the next child
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild # If there is still a child of the node object on its right
# AND if the distance is ok, return the next child
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild # If the function arrives here, the generator will be considered empty
# there is no more than two values: the left and the right children

调用者:

Create an empty list and a list with the current object reference

result, candidates = list(), [self]

Loop on candidates (they contain only one element at the beginning)

while candidates:

# Get the last candidate and remove it from the list
node = candidates.pop() # Get the distance between obj and the candidate
distance = node._get_dist(obj) # If distance is ok, then you can fill the result
if distance <= max_dist and distance >= min_dist:
result.extend(node._values) # Add the children of the candidate in the candidate's list
# so the loop will keep running until it will have looked
# at all the children of the children of the children, etc. of the candidate
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))

return result
此代码包含几个智能部分:

循环在列表上迭代,但在循环迭代时列表会扩展。 这是一种简洁的方式来遍历所有这些嵌套数据,即使它有点危险,因为你最终可能会有一个无限循环。 在这种情况下,candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))耗尽了生成器的所有值,但是while不断创建新的生成器对象,这些对象将产生与以前的值不同的值,因为它不在同一个节点上应用。

extend()方法是一个列表对象方法,它期望一个可迭代的,并将其值添加到列表中。

通常我们会传递一个列表给它:

a = [1, 2]
b = [3, 4]
a.extend(b)
print(a)
[1, 2, 3, 4]
但是在你的代码中,它得到了一个生成器,这很好,因为:

您不需要读取两次值。
你可能有很多孩子,你不希望他们都存储在内存中。
它的工作原理是因为Python不关心方法的参数是否是列表。 Python需要迭代器,因此它将与字符串、列表、元组和生成器一起工作! 这被称为duck typing,也是Python如此酷的原因之一。 但这是另一个故事,另一个问题。..

你可以在这里停下来,或者读一点,看看生成器的高级使用:

控制发电机耗尽

class Bank(): # Let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "100
print(corner_street_atm.next())
100', '100', '100']
hsbc.crisis = True # Crisis is coming, no more money!
print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
for cash in brand_new_atm:
... print cash
100
100
100
a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]
但是在你的代码中,它得到了一个生成器,这很好,因为:

您不需要读取两次值。
你可能有很多孩子,你不希望他们都存储在内存中。
它的工作原理是因为Python不关心方法的参数是否是列表。 Python需要迭代器,因此它将与字符串、列表、元组和生成器一起工作! 这被称为duck typing,也是Python如此酷的原因之一。 但这是另一个故事,另一个问题。..

你可以在这里停下来,或者读一点,看看生成器的高级使用:

控制发电机耗尽
>>> class Bank(): # Let's create a bank, building ATMs
... crisis = False
... def create_atm(self):
... while not self.crisis:
... yield "100
>>> print(corner_street_atm.next())
100', '100', '100']
>>> hsbc.crisis = True # Crisis is coming, no more money!
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
... print cash
100
100
100
100
100"
>>> hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
100
>>> print([corner_street_atm.next() for cash in range(5)])
['100', '100', '100
100
100
100
100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))

它对于控制对资源的访问等各种事情都很有用。

Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?

那么就import itertools。

一个例子? 让我们来看看四匹马比赛的可能到达顺序:

horses = [1, 2, 3, 4]
races = itertools.permutations(horses)
print(races)
<itertools.permutations object at 0xb754f1dc>
print(list(itertools.permutations(horses)))
hsbc = Bank() # When everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
100
>>> print([corner_street_atm.next() for cash in range(5)])
['100', '100', '100
100
100
100
100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))

它对于控制对资源的访问等各种事情都很有用。

Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?

那么就import itertools。

一个例子? 让我们来看看四匹马比赛的可能到达顺序:

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
print(corner_street_atm.next())
100
>>> print([corner_street_atm.next() for cash in range(5)])
['100', '100', '100
100
100
100
100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))

它对于控制对资源的访问等各种事情都很有用。

Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?

那么就import itertools。

一个例子? 让我们来看看四匹马比赛的可能到达顺序:

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs
>>> print(wall_street_atm.next())
<type 'exceptions.StopIteration'>
>>> hsbc.crisis = False # The trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
<type 'exceptions.StopIteration'>
>>> brand_new_atm = hsbc.create_atm() # Build a new one to get back in business
>>> for cash in brand_new_atm:
... print cash
100
100
100
100
$100
...
注意:对于Python3,使用print(corner_street_atm.next())或print(next(corner_street_atm))

它对于控制对资源的访问等各种事情都很有用。

Itertools,你最好的朋友
itertools模块包含用于操作iterables的特殊函数。 曾经想复制一个发电机吗? 链两个发电机? 在一个单行嵌套列表中分组值? Map / Zip不创建另一个列表?

那么就import itertools。

一个例子? 让我们来看看四匹马比赛的可能到达顺序:

>>> horses = [1, 2, 3, 4]
>>> races = itertools.permutations(horses)
>>> print(races)
<itertools.permutations object at 0xb754f1dc>
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
理解迭代的内在机制
迭代是一个隐含iterables(实现iter()方法)和iterators(实现next()方法)的过程。 Iterables是您可以从中获取迭代器的任何对象。 迭代器是允许您迭代可迭代对象的对象。

Python中`yield`关键字详解的更多相关文章

  1. 【转载】C/C++中extern关键字详解

    1 基本解释:extern可以置于变量或者函数前,以标示变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义.此外extern也可用来进行链接指定. 也就是说extern ...

  2. python中threading模块详解(一)

    python中threading模块详解(一) 来源 http://blog.chinaunix.net/uid-27571599-id-3484048.html threading提供了一个比thr ...

  3. Python中time模块详解

    Python中time模块详解 在平常的代码中,我们常常需要与时间打交道.在Python中,与时间处理有关的模块就包括:time,datetime以及calendar.这篇文章,主要讲解time模块. ...

  4. 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类

    第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一.    引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ...

  5. yield关键字详解与三种用法

    本篇文章比较硬核, 适合有一定Python基础的读者阅读, 如果您对Python还不甚了解可以先关注我哦, 我会持续更新Python技术文章 yield详解 yield与return相同每次调用都会返 ...

  6. JS中this关键字详解

    本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 阅读此文章,还需要心平气和的阅读完,相信一定会有所收获,我也会不定期的发布,分享一些文章,共同学习 首先,必须搞清楚在JS里面,函数 ...

  7. JS 中 this 关键字详解

    本文主要解释在JS里面this关键字的指向问题(在浏览器环境下). 首先,必须搞清楚在JS里面,函数的几种调用方式: 普通函数调用 作为方法来调用 作为构造函数来调用 使用apply/call方法来调 ...

  8. python中常用模块详解二

    log模块的讲解 Python 使用logging模块记录日志涉及四个主要类,使用官方文档中的概括最为合适: logger提供了应用程序可以直接使用的接口API: handler将(logger创建的 ...

  9. 76.Python中F表达式详解

    F表达式是用来优化ORM操作数据库的. 举个例子:我们做口罩的公司要将所有员工的薪水增加2000元,如果按照正常的流程,应该是先从数据库中提取所有的员工的工资到Python内存中,然后使用Python ...

  10. python 中的unicode详解

    通过例子来看问题是比较容易懂的. 首先来看,下面这个是我新建的一个txt文件,名字叫做ivan_utf8.txt,然后里面随便编辑了一些东西. 然后来用控制台打开这个文件,同样也是截图: 这里就是简单 ...

随机推荐

  1. 比Nginx更好用的Gateway!

    比Nginx更好用的Gateway! Token新开源Gateway,使用yarp实现的一个反向代理,支持界面操作动态添加集群添加路由绑定,并且支持动态添加域名绑定https证书,超强yarp+Fre ...

  2. [转帖]疑问:进程在竞争CPU时并没有真正运行,为什么还会导致系统的负载升高?

    疑问:进程在竞争CPU时并没有真正运行,为什么还会导致系统的负载升高? 因为存在CPU上下文切换. linux系统说明 Linux是一个多任务操作系统,它支持远大于CPU数量的任务同时运行.当然,这些 ...

  3. 【K哥爬虫普法】淘宝一亿快递信息泄漏,有人正在盯着你的网购!

    我国目前并未出台专门针对网络爬虫技术的法律规范,但在司法实践中,相关判决已屡见不鲜,K 哥特设了"K哥爬虫普法"专栏,本栏目通过对真实案例的分析,旨在提高广大爬虫工程师的法律意识, ...

  4. ABP Vnext 微服务 常见问题

    1.token问题 原因:拿token和认证token的服务器不一致 2.minio访问报错 minio错误 S3 API Request made to Console port. S3 R 解决方 ...

  5. Gin 框架之Cookie与Session

    目录 一.Cookie和Session的由来 二.Cookie简介 1. 什么是Cookie 2. Cookie规范 3. 安全性 4. Cookie 关键配置 三.Session简介 1. 什么是S ...

  6. 开发QQ官方机器人

    QQ 频道机器人开发简明教程 1. 简介 QQ 频道机器人是一种可以在 QQ 频道中与用户进行互动的服务.这个教程旨在帮助新手学习如何使用 Python 的官方SDK,快速实现一些基本的机器人功能. ...

  7. LINQ分组排序后获取每组第一条记录

    当前有一张数据表{Student},包含了如下的字段信息: CREATE TABLE [dbo].[Student]( [Sno] [nchar](7) NOT NULL, [Sname] [ncha ...

  8. 离线下载和安装UWP(windows应用商店)软件

    离线下载uwp安装包 打开商店,然后搜索您要的应用程序名称,进入应用界面 点击 分享按钮,在弹出窗口中选择[复制链接] 把链接粘贴到:https://store.rg-adguard.net/ 默认选 ...

  9. 独立安装VS的C++编译器build tools

    Microsoft C++ 生成工具 Microsoft C++ 生成工具 - Visual Studio Microsoft C++ 生成工具通过可编写脚本的独立安装程序提供 MSVC 工具集,无需 ...

  10. 剪粘板增强小工具(可多次Ctrl+V)

    前言 windows的剪贴板中存储是的最新一次的复制结果,比如先复制A,再复制B,C,在按下粘贴键时粘贴的是最后一次的结果C,在工作时有时候会遇到需要多次复制粘贴的情景,我就在思考有没有一款工具可以保 ...