栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

python中“ yield”关键字有什么作用?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

python中“ yield”关键字有什么作用?

要了解其

yield
作用,你必须了解什么是生成器。并且,在你了解生成器之前,你必须了解
iterables

可迭代

创建列表时,可以一一阅读它的项目。逐一读取其项称为迭代:

>>> mylist = [1, 2, 3]>>> for i in mylist:...    print(i)123

mylist
是一个可迭代的。当你使用列表推导时,你将创建一个列表,因此是可迭代的:

>>> mylist = [x*x for x in range(3)]>>> for i in mylist:...    print(i)014

你可以使用的所有“ for… in…”都是可迭代的;lists,strings,文件…

这些可迭代的方法很方便,因为你可以随意读取它们,但是你将所有值都存储在内存中,当拥有很多值时,这并不总是想要的。

发电机

生成器是迭代器,一种迭代,你只能迭代一次。生成器不会将所有值存储在内存中,它们会即时生成值:

>>> mygenerator = (x*x for x in range(3))>>> for i in mygenerator:...    print(i)014

只是你使用()代替一样[]。但是,由于生成器只能使用一次,因此你无法执行for i in mygenerator第二次:生成器先计算0,然后将其忽略,然后计算1,最后一次计算4。

产量

yield
是与一样使用的关键字
return
,不同之处在于该函数将返回生成器。

>>> def createGenerator():...    mylist = range(3)...    for i in mylist:...        yield i*i...>>> mygenerator = createGenerator() # create a generator>>> print(mygenerator) # mygenerator is an object!<generator object createGenerator at 0xb7555c34>>>> for i in mygenerator:...     print(i)014

这是一个无用的示例,但是当你知道函数将返回大量的值(只需要读取一次)时,它就很方便。

要掌握

yield
,你必须了解在调用函数时,在函数主体中编写的代码不会运行。该函数仅返回生成器对象,这有点棘手:-)

然后,你的代码将在每次

for
使用生成器时从中断处继续。

现在最困难的部分是:

第一次

for
调用从你的函数创建的生成器对象时,它将从头开始运行函数中的代码,直到命中为止yield,然后它将返回循环的第一个值。然后,彼此调用将再次运行你在函数中编写的循环,并返回下一个值,直到没有值可返回为止。

一旦函数运行,该生成器就被认为是空的,但

yield
不再起作用。可能是因为循环已结束,或者是你不再满足
"if/else"
于此。

你的代码说明
发电机:

# Here you create the method of the node object that will return the generatordef _get_child_candidates(self, distance, min_dist, max_dist):    # Here is the pre 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 referenceresult, 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]

但是在你的代码中,它得到了一个生成器,这很好,因为:

  1. 你不需要两次读取值。
  2. 你可能有很多孩子,并且你不希望所有孩子都存储在内存中。

它之所以有效,是因为Python不在乎方法的参数是否为列表。Python期望可迭代,因此它将与字符串,列表,元组和生成器一起使用!这就是所谓的鸭子输入,这是Python如此酷的原因之一。但这是另一个故事,另一个问题……

你可以在此处停止,或者阅读一点以了解生成器的高级用法:

控制发电机耗尽

>>> class Bank(): # Let's create a bank, building ATMs...    crisis = False...    def create_atm(self):...        while not self.crisis:... yield "$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())$100>>> print([corner_street_atm.next() for cash in range(5)])['$100', '$100', '$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$100$100$100$100...

注意:对于Python 3,请使用

print(corner_street_atm.__next__())
print(next(corner_street_atm))

对于诸如控制对资源的访问之类的各种事情,它可能很有用。

Itertools,你最好的朋友
itertools模块包含用于操纵可迭代对象的特殊功能。曾经希望复制一个发电机吗?连锁两个发电机?用一个班轮对嵌套列表中的值进行分组?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)]

了解迭代的内部机制

迭代是一个过程,意味着可迭代(实现

__iter__()
方法)和迭代器(实现
__next__()
方法)。可迭代对象是可以从中获取迭代器的任何对象。迭代器是使你可以迭代可迭代对象的对象。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/365260.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号