发布于2019-08-19 21:33 阅读(1989) 评论(0) 点赞(3) 收藏(2)
yield
Python中关键字的用途是什么?它有什么作用?
例如,我试图理解这段代码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
它的作用,您必须了解生成器是什么。在您了解生成器之前,您必须了解可迭代物。
创建列表时,您可以逐个阅读其项目。逐个读取它的项称为迭代:
>>> 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
,文件...
这些迭代很方便,因为您可以根据需要阅读它们,但是您将所有值存储在内存中,当您拥有大量值时,这并不总是您想要的。
生成器是迭代器,是一种只能迭代一次的迭代器。生成器不会将所有值存储在内存中,它们会动态生成值:
>>> 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]
但是在你的代码中它得到了一个生成器,这很好,因为:
它的工作原理是因为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模块包含操作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黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 python黑洞网 All Rights Reserved 版权所有,并保留所有权利。 京ICP备18063182号-1
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!