理解什么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,一个一个。
产量d
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
。这可能是因为循环已经结束,或者因为你不再满足"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 are 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 the distance is ok, then you can fill in the result
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
# Add the children of the candidate to the candidate's list
# so the loop will keep running until it has 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 期望它能用字符串、列表、图普勒和生成器来操作。 这叫做鸭字打字, 也是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, 用于 Python 3, 使用print(corner_street_atm.__next__())
或print(next(corner_street_atm))
它可以对控制获取资源等各种事情有用。
义大便,你最好的朋友
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__()
循环是您可以从中获取迭代器的任何对象。迭代器是允许您在迭代器上迭代的对象。
这篇文章中更多关于如何如何for
环环工作.