|
yieldPython关键词有什么用?它有什么作用?
: g. F/ H7 Q! _5 `/ f; }! C例如,我试图理解这个代码1:
9 {6 l8 c) \/ ~def _get_child_candidates(self,distance,min_dist,max_dist): if self._leftchild and distance - max_dist = self._median: yield self._rightchild O1 l8 N& w$ |
调用者:, {" P4 q1 |0 y8 `
result,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
3 ~& H0 r c8 v) {. m4 @7 q _get_child_candidates调用方法会发生什么?是否返回列表?单个元素?又叫了吗?后续呼叫什么时候停止?
. P7 g$ O! [0 e" K # }- ~- t7 x( o) W8 Q. \" _$ Z- t
解决方案:
T( `9 n, i% d: }+ r 要了解yield你必须了解它的作用生成器是什么?在了解生成器之前,你必须知道iterables。
0 ?/ W& R; f6 V可迭代对象在创建列表时,您可以逐一阅读其项目。一个接一个地读取它的项目称为迭代:
; N9 x' m; B% b( E>>> mylist = [1,2,3]>>> for i in mylist:... print(i)123
$ U! Q5 q! Z8 w1 R* Q( O3 x mylist是一个可迭代的。当您使用列表推导式时,您创建了一个列表,因此它是一个可迭代的对象:0 _/ ^( |: h+ {/ w% ^1 A% ~. O- I
>>> mylist = [x*x for x in range(3)]>>> for i in mylist:... print(i)0142 J% p( V* H4 \
可以用 for... in...所有内容都是可迭代的;lists,strings,文件…
7 V2 ~( T# Q5 o1 b7 V3 T8 L7 E这些可迭代对象非常方便,因为你可以随意阅读它们,但当你有很多值时,它们并不总是你想要的。* {/ _2 X6 r! A, u
Generators生成器是一种迭代器可迭代对象只能迭代一次。生成器不会将所有值存储在内存中,它们会立即产生成值:
6 Z7 M1 Y& ]& p- X7 `' [# O>>> mygenerator = (x*x for x in range(3))>>> for i in mygenerator:... print(i)014
* K6 k9 m. C% J( p0 ^/ }0 ^ 除了使用()而不是[]. 但是,您不能执行for i in mygenerator第二次,因为生成器只能使用一次:它们计算 0,然后忘记它,计算 1,然后逐一计算 4。
! F( a* q" k7 ?7 Q2 ^. }0 |$ DYieldyield它是一个像 一样使用的关键字return,除了该函数将返回一个生成器。3 F, |' C7 x7 k) q
>>> 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 t' {# P z6 ?
这是一个无用的例子,但当你知道你的函数会返回很多你只需要读一次的值时,它会很方便。
2 t' n% q( P% P2 y5 ^: k$ T+ v要掌握yield,你必须明白,当您调用函数时,函数体中写的代码没有运行。这个函数只返回生成器对象,有点棘手。
- `" k& o% E w1 } W$ w然后,你的代码每次都会出现for从停止的地方继续使用生成器。& X* P! @! c' P9 ~9 [- `% z
现在是困难的部分:1 `% | K9 G$ R N0 K P2 S
第一次for调用从您的函数创建的生成器对象时,它将从零开始运行您的函数中的代码,直到命中yield,然后它将返回到循环的第一个值。然后,每个后续调用程序将操作您在函数中编写的循环的另一个迭代,并返回到下一个值。这将持续到生成器被认为是空的,当函数运行时不点击 yield。这可能是因为循环已经结束,或者因为你不再满意"if/else".8 T) j6 z$ x8 D. @4 A% {4 h9 ], o
你的代码解释Generator:- ]* n3 Z3 Z# x7 y
# 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* A. F. w, ?! `# I
Caller:, B+ D2 K8 y. D C
# 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
6 B; y% u5 }8 k: k2 H/ U1 x4 x5 a 该代码包含几个智能部分:/ A8 `7 C0 m+ h( Z) @. b& A6 D# y
循环迭代列表,但列表在循环迭代时会扩展。这是一种简单的方法,遍历所有这些嵌套数据,即使有点危险,因为你最终可能会陷入无限循环。在这种情况下,candidates.extend(node._get_child_candidates(distance,min_dist,max_dist))耗尽生成器的所有值,但while由于没有应用于同一节点,不断创建新的生成器对象会产生与以前不同的值。
5 _6 t$ O6 ]2 U, F该extend()方法是列表对象的方法,它需要一个可迭代的对象,并将其值添加到列表中。通常我们会给它发一个列表: D* f0 R+ l% H6 |. B# ~
>>> a = [1,2]>>> b = [3,4]>>> a.extend(b)>>> print(a)[1,2,3,4]4 m1 q- B: C+ Q+ Q1 G) F3 K
但是在你的代码中,它得到了一个生成器,因为:
! p2 b- }* q4 |- p/ q( a( t# @[ol]这些值不需要读两次。
1 C9 g* l( t" s) R+ M% _0 R. ^你可能有很多孩子,你不希望他们都存储在内存中。[/ol]它之所以有效是因为 Python 不在乎方法参数是否列表。Python 需要可迭代对象,因此可以处理字符串、列表、元组和生成器!这叫鸭型,也叫 Python 这么酷的原因之一。但这是另一个故事,另一个问题......
3 \6 i2 g" K2 g( ^您可以停在这里,也可以阅读生成器的先进用法:3 u" n0 G' T5 {& M) G+ K/ t
Controlling 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...
' O2 W- E5 W4 H- X. S 注意:对于 Python 3,使用print(corner_street_atm.__next__())或print(next(corner_street_atm))$ r7 i0 y/ n9 n* v7 o* @- {4 \* z
它可以用来控制访问等各种事情。$ E2 Z/ W/ ?/ e7 `5 S
Itertools,你最好的朋友itertools 模块包含操作可迭代对象的特殊函数。你想复制一个生成器吗?连接两个发电机?用单行分组嵌套列表中的值?Map / Zip不要创建另一个列表?
5 {' P( `6 N1 |$ @4 J& A0 D那么就import itertools.
/ _ z+ E5 {2 M5 R) u- q1 X' i) S一个例子?让我们来看看四马可能的到达顺序:& t, A$ k! O- r# R! A$ P
[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__()方法)过程。可迭代对象是您可以从中获得的任何对象。迭代器是您可以迭代可迭代对象的对象。
! D3 d2 k0 k& `! B" w" }5 T这篇文章有更多关于如何循环的问题for工作内容。 |
|