程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

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

发布于2019-08-19 21:33     阅读(1989)     评论(0)     点赞(3)     收藏(2)


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

例如,我试图理解这段代码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  

这是来电者:

result, candidates = [], [self]
while candidates:
    node = candidates.pop()
    distance = node._get_dist(obj)
    if distance <= max_dist and distance >= min_dist:
        result.extend(node._values)
    candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result

_get_child_candidates调用该方法时会发生什么列表是否返回?单个元素?它又被召唤了吗?后续通话何时停止?


这段代码是由Jochen Schulz(jrschulz)编写的,他为度量空间创建了一个很棒的Python库。这是完整源代码的链接:模块mspace


解决方案


要了解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...迭代的; listsstrings,文件...

这些迭代很方便,因为您可以根据需要阅读它们,但是您将所有值存储在内存中,当您拥有大量值时,这并不总是您想要的。

发电机

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

>>> 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 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)
0
1
4

这是一个无用的例子,但是当你知道你的函数将返回一组你只需要阅读一次的大量值时它会很方便。

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

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

现在困难的部分:

第一次for从函数调用生成器对象时,它将从头开始运行函数中的代码,直到它命中yield,然后它将返回循环的第一个值。然后,每个其他调用将再次运行您在函数中写入的循环,并返回下一个值,直到没有值返回。

一旦函数运行,生成器被认为是空的,但是不再命中yield这可能是因为循环已经结束,或者因为你不再满足"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 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 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 candidates 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()方法是一个列表对象方法,它需要一个iterable并将其值添加到列表中。

通常我们将列表传递给它:

>>> a = [1, 2]
>>> b = [3, 4]
>>> a.extend(b)
>>> print(a)
[1, 2, 3, 4]

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

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

它的工作原理是因为Python不关心方法的参数是否是列表。Python期望iterables所以它将适用于字符串,列表,元组和生成器!这叫做鸭子打字,这也是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模块包含操作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)]

理解迭代的内在机制

迭代是一个暗示迭代(实现__iter__()方法)和迭代器(实现__next__()方法)的过程。Iterables是您可以从中获取迭代器的任何对象。迭代器是允许您迭代迭代的对象。

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



所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:https://www.pythonheidong.com/blog/article/48887/ad78981682f78b120c3e/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

3 0
收藏该文
已收藏

评论内容:(最多支持255个字符)