|
yieldPython关键词有什么用?它有什么作用?6 A0 u% v7 i% G9 Z9 E; q
例如,我试图理解这个代码1:& w/ i v6 x. J
def _get_child_candidates(self,distance,min_dist,max_dist): if self._leftchild and distance - max_dist = self._median: yield self._rightchild 0 K9 X0 C& G i/ P8 F% h3 U
调用者:
- T" Z' e0 i! Rresult,candidates = [],[self]while candidates: node = candidates.pop() distance = node._get_dist(obj) if distance = min_dist: result.extend(node._values) candidates.extend(node._get_child_candidates(distance,min_dist,max_dist))return result& ~! ~$ f/ ^0 p3 K `0 @ B0 [, H
_get_child_candidates调用方法会发生什么?是否返回列表?单个元素?又叫了吗?后续呼叫什么时候停止?
w @" u1 l# D& r9 B) `
, w: d2 x+ G5 Q. i 解决方案: ' _' n( _' H% ?$ K/ l- _) ^
要了解yield你必须了解它的作用生成器是什么?在了解生成器之前,你必须知道iterables。2 H7 E6 l% E2 K8 C, T1 ~
可迭代对象在创建列表时,您可以逐一阅读其项目。一个接一个地读取它的项目称为迭代: g7 s& x( k* B" V8 b; x
>>> mylist = [1,2,3]>>> for i in mylist:... print(i)1232 N% S# U( ?. s; `7 U) y, o
mylist是一个可迭代的。当您使用列表推导式时,您创建了一个列表,因此它是一个可迭代的对象:
) t4 p* e9 w: t4 Z6 Z5 i>>> mylist = [x*x for x in range(3)]>>> for i in mylist:... print(i)014+ e$ n; O9 Q5 @ e# E1 ?' \
可以用 for... in...所有内容都是可迭代的;lists,strings,文件…+ H7 \6 m3 b3 j% S
这些可迭代对象非常方便,因为你可以随意阅读它们,但当你有很多值时,它们并不总是你想要的。
. b# F |4 F8 j6 PGenerators生成器是一种迭代器可迭代对象只能迭代一次。生成器不会将所有值存储在内存中,它们会立即产生成值:% g( P& N! Z% A8 E$ d8 b
>>> mygenerator = (x*x for x in range(3))>>> for i in mygenerator:... print(i)014
v" e0 m- Y0 @- d2 s 除了使用()而不是[]. 但是,您不能执行for i in mygenerator第二次,因为生成器只能使用一次:它们计算 0,然后忘记它,计算 1,然后逐一计算 4。* c' z* p4 ]; O& ^0 t6 b
Yieldyield它是一个像 一样使用的关键字return,除了该函数将返回一个生成器。
, K( r5 M6 ?: D0 u" X9 \7 j>>> 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!>>> for i in mygenerator:... print(i)014 m7 P5 a8 G4 q8 Z3 ?" l
这是一个无用的例子,但当你知道你的函数会返回很多你只需要读一次的值时,它会很方便。" m0 Y6 c9 M/ [( ?, i
要掌握yield,你必须明白,当您调用函数时,函数体中写的代码没有运行。这个函数只返回生成器对象,有点棘手。
1 [( I; n, T; _ N( E) O' P4 ~然后,你的代码每次都会出现for从停止的地方继续使用生成器。
$ S. s! \" B u$ K# A现在是困难的部分:
- b# ?2 R+ q) A5 o第一次for调用从您的函数创建的生成器对象时,它将从零开始运行您的函数中的代码,直到命中yield,然后它将返回到循环的第一个值。然后,每个后续调用程序将操作您在函数中编写的循环的另一个迭代,并返回到下一个值。这将持续到生成器被认为是空的,当函数运行时不点击 yield。这可能是因为循环已经结束,或者因为你不再满意"if/else".
* a( S4 D; P1 z3 R; y8 t你的代码解释Generator:/ g6 n1 p4 N0 M& _
# 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 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._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
f0 l& } v6 }, l1 P* s- Q/ Y& l- M Caller:) d+ k$ H, M* \7 C3 M1 `
# 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 = 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
: t" l4 T4 n0 I- q/ @, Z 该代码包含几个智能部分:
- V" w+ S: D0 D( Z8 s- p8 v. J循环迭代列表,但列表在循环迭代时会扩展。这是一种简单的方法,遍历所有这些嵌套数据,即使有点危险,因为你最终可能会陷入无限循环。在这种情况下,candidates.extend(node._get_child_candidates(distance,min_dist,max_dist))耗尽生成器的所有值,但while由于没有应用于同一节点,不断创建新的生成器对象会产生与以前不同的值。
+ @$ R$ L" I7 r% ^该extend()方法是列表对象的方法,它需要一个可迭代的对象,并将其值添加到列表中。通常我们会给它发一个列表:) q0 [ f, r" z/ G$ V: v
>>> a = [1,2]>>> b = [3,4]>>> a.extend(b)>>> print(a)[1,2,3,4]
: H0 V1 M6 K/ Y' @& ^ 但是在你的代码中,它得到了一个生成器,因为:8 @, u( J' y- C
[ol]这些值不需要读两次。
& R. `+ k3 L, O- Y! Q# k7 |* t/ ?: K你可能有很多孩子,你不希望他们都存储在内存中。[/ol]它之所以有效是因为 Python 不在乎方法参数是否列表。Python 需要可迭代对象,因此可以处理字符串、列表、元组和生成器!这叫鸭型,也叫 Python 这么酷的原因之一。但这是另一个故事,另一个问题......; j* `$ w: J( A
您可以停在这里,也可以阅读生成器的先进用法:
+ v% r A' K6 v: qControlling a generator exhaustion>>> 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())>>> wall_street_atm = hsbc.create_atm() # It's even true for new ATMs>>> print(wall_street_atm.next())>>> hsbc.crisis = False # The trouble is,even post-crisis the ATM remains empty>>> print(corner_street_atm.next())>>> 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...1 T' y/ t" R* `3 \, _
注意:对于 Python 3,使用print(corner_street_atm.__next__())或print(next(corner_street_atm))% ^. r7 i0 P7 K# p
它可以用来控制访问等各种事情。9 `) j6 E/ g' D5 D& I& b( l
Itertools,你最好的朋友itertools 模块包含操作可迭代对象的特殊函数。你想复制一个生成器吗?连接两个发电机?用单行分组嵌套列表中的值?Map / Zip不要创建另一个列表?
7 N: M0 z7 F7 s) D( k) b4 [$ ~$ ? w那么就import itertools.4 F# e% U3 h2 t( r! i9 ?# B2 g
一个例子?让我们来看看四马可能的到达顺序:4 ^3 l% X- d# |/ H5 ^ {
[code]>>> horses = >>> races = itertools.permutations(horses)>>> print(races)<i>>>> print(list(itertools.permutations(horses)))(1、2、3、4)、(1、2、4、3)、(1、3、2、4)、(1、3、4、4、2)、(1、4、2、3、2)、(2、1、3、3、4)、(2、1、4、3、3、4、3、2、2、3、4、4、4、4、4、4、4、4、4、4、4、4、4、4、3、3、4、4、4、3、4、4、3、4、4、3、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、3、4、4、3、4、4、3、4、3、4、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、3、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4、4(4、1、2、3)、(4、1、3、2)、(4、2、1、3)、(4、2、3、1)、(4、3、1、2)code]了解迭代的内在机制迭代是包含可迭代对象(实现)__iter__()方法)和迭代器(实现)__next__()方法)过程。可迭代对象是您可以从中获得的任何对象。迭代器是您可以迭代可迭代对象的对象。- T# V. T# Z' {/ z+ z2 R& I
这篇文章有更多关于如何循环的问题for工作内容。 |
|