外贸soho 网站建设,php空间购买,动态可视化wps图表制作,合肥设网站首先#xff0c;如果你还没有对yield有个初步分认识#xff0c;那么你先把yield看做“return”#xff0c;这个是直观的#xff0c;它首先是个return#xff0c;普通的return是什么意思#xff0c;就是在程序中返回某个值#xff0c;返回之后程序就不再往下运行了。看做…首先如果你还没有对yield有个初步分认识那么你先把yield看做“return”这个是直观的它首先是个return普通的return是什么意思就是在程序中返回某个值返回之后程序就不再往下运行了。看做return之后再把它看做一个是生成器generator的一部分带yield的函数才是真正的迭代器好了如果你对这些不明白的话那先把yield看做return,然后直接看下面的程序你就会明白yield的全部意思了
def foo():print(starting...)while True:res yield 4print(res:,res)
g foo()
print(next(g))
print(**20)
print(next(g))就这么简单的几行代码就让你明白什么是yield代码的输出这个
starting...
4
********************
res: None
4 我直接解释代码运行顺序相当于代码单步调试
1.程序开始执行以后因为foo函数中有yield关键字所以foo函数并不会真的执行而是先得到一个生成器g(相当于一个对象)
2.直到调用next方法foo函数正式开始执行先执行foo函数中的print方法然后进入while循环
3.程序遇到yield关键字然后把yield想想成return,return了一个4之后程序停止并没有执行赋值给res操作此时next(g)语句执行完成所以输出的前两行第一个是while上面的print的结果,第二个是return出的结果是执行print(next(g))的结果
4.程序执行print(**20)输出20个*
5.又开始执行下面的print(next(g)),这个时候和上面那个差不多不过不同的是这个时候是从刚才那个next程序停止的地方开始执行的也就是要执行res的赋值操作这时候要注意这个时候赋值操作的右边是没有值的因为刚才那个是return出去了并没有给赋值操作的左边传参数所以这个时候res赋值是None,所以接着下面的输出就是res:None,
6.程序会继续在while里执行又一次碰到yield,这个时候同样return 出4然后程序停止print函数输出的4就是这次return出的4. 到这里你可能就明白yield和return的关系和区别了带yield的函数是一个生成器而不是一个函数了这个生成器有一个函数就是next函数next就相当于“下一步”生成哪个数这一次的next开始的地方是接着上一次的next停止的地方执行的所以调用next的时候生成器并不会从foo函数的开始执行只是接着上一步停止的地方开始然后遇到yield后return出要生成的数此步就结束。
def foo():print(starting...)while True:res yield 4print(res:,res)
g foo()
print(next(g))
print(**20)
print(g.send(7))再看一个这个生成器的send函数的例子这个例子就把上面那个例子的最后一行换掉了输出结果
starting...
4
********************
res: 7
4
先大致说一下send函数的概念此时你应该注意到上面那个的紫色的字还有上面那个res的值为什么是None这个变成了7到底为什么这是因为send是发送一个参数给res的因为上面讲到return的时候并没有把4赋值给res下次执行的时候只好继续执行赋值操作只好赋值为None了而如果用send的话开始执行的时候先接着上一次return 4之后执行先把7赋值给了res,然后执行next的作用遇见下一回的yieldreturn出结果后结束。 5.程序执行g.send(7)程序会从yield关键字那一行继续向下运行send会把7这个值赋值给res变量
6.由于send方法中包含next()方法所以程序会继续向下运行执行print方法然后再次进入while循环
7.程序执行再次遇到yield关键字yield会返回后面的值后程序再次暂停直到再次调用next方法或send方法。
这就结束了说一下为什么用这个生成器是因为如果用List的话会占用更大的空间比如说取0,1,2,3,4,5,6............1000
你可能会这样
for n in range(1000):an
这个时候range(1000)就默认生成一个含有1000个数的list了所以很占内存。
这个时候你可以用刚才的yield组合成生成器进行实现也可以用xrange(1000)这个生成器实现
yield组合
def foo(num):print(starting...)while num10:numnum1yield num
for n in foo(0):print(n)
输出
starting...
1
2
3
4
5
6
7
8
9
10
xrange(1000):
for n in xrange(1000):an 其中要注意的是python3时已经没有xrange()了在python3中range()就是xrange()了你可以在python3中查看range()的类型它已经是个class range了而不是一个list了毕竟这个是需要优化的。
转载自https://blog.csdn.net/mieleizhi0522/article/details/82142856
3. (译)Python关键字yield的解释(stackoverflow)¶
译者:hit9原文:http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained译者注:这是stackoverflow上一个很热的帖子这里是投票最高的一个答案
Contents
(译)Python关键字yield的解释(stackoverflow) 提问者的问题回答部分可迭代对象生成器yield关键字回到你的代码控制生成器的穷尽Itertools,你最好的朋友了解迭代器的内部机理
3.1. 提问者的问题¶
Python关键字yield的作用是什么用来干什么的
比如我正在试图理解下面的代码: def node._get_child_candidates(self, distance, min_dist, max_dist):if self._leftchild and distance - max_dist self._median:yield self._leftchildif self._rightchild and distance max_dist self._median:yield self._rightchild下面的是调用: result, candidates list(), [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 的时候发生了什么返回了一个列表返回了一个元素被重复调用了么 什么时候这个调用结束呢
3.2. 回答部分¶
为了理解什么是 yield,你必须理解什么是生成器。在理解生成器之前让我们先走近迭代。
3.3. 可迭代对象¶
当你建立了一个列表你可以逐项地读取这个列表这叫做一个可迭代对象: mylist [1, 2, 3]for i in mylist :
... print(i)
1
2
3mylist 是一个可迭代的对象。当你使用一个列表生成式来建立一个列表的时候就建立了一个可迭代的对象: mylist [x*x for x in range(3)]for i in mylist :
... print(i)
0
1
4所有你可以使用 for .. in .. 语法的叫做一个迭代器列表字符串文件……你经常使用它们是因为你可以如你所愿的读取其中的元素但是你把所有的值都存储到了内存中如果你有大量数据的话这个方式并不是你想要的。
3.4. 生成器¶
生成器是可以迭代的但是你 只可以读取它一次 因为它并不把所有的值放在内存中它是实时地生成数据: mygenerator (x*x for x in range(3))for i in mygenerator :
... print(i)
0
1
4看起来除了把 [] 换成 () 外没什么不同。但是你不可以再次使用 for i in mygenerator , 因为生成器只能被迭代一次先计算出0然后继续计算1然后计算4一个跟一个的…
3.5. yield关键字¶
yield 是一个类似 return 的关键字只是这个函数返回的是个生成器。 def createGenerator() :
... mylist range(3)
... for i in mylist :
... yield i*i
...mygenerator createGenerator() # create a generatorprint(mygenerator) # mygenerator is an object!
generator object createGenerator at 0xb7555c34for i in mygenerator:
... print(i)
0
1
4这个例子没什么用途但是它让你知道这个函数会返回一大批你只需要读一次的值.
为了精通 yield ,你必须要理解当你调用这个函数的时候函数内部的代码并不立马执行 这个函数只是返回一个生成器对象这有点蹊跷不是吗。
那么函数内的代码什么时候执行呢当你使用for进行迭代的时候.
现在到了关键点了
第一次迭代中你的函数会执行从开始到达 yield 关键字然后返回 yield 后的值作为第一次迭代的返回值. 然后每次执行这个函数都会继续执行你在函数内部定义的那个循环的下一次再返回那个值直到没有可以返回的。
如果生成器内部没有定义 yield 关键字那么这个生成器被认为成空的。这种情况可能因为是循环进行没了或者是没有满足 if/else 条件。
3.6. 回到你的代码¶
(译者注:这是回答者对问题的具体解释)
生成器: # Here you create the method of the node object that will return the generator
def node._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 childif 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 childif 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 listnode candidates.pop()# Get the distance between obj and the candidatedistance node._get_dist(obj)# If distance is ok, then you can fill the resultif 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 candidatecandidates.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只希望它是个可以迭代的所以这个参数可以是列表元组字符串生成器... 这叫做 duck typing,这也是为何Python如此棒的原因之一但这已经是另外一个问题了...
你可以在这里停下来看看生成器的一些高级用法:
3.7. 控制生成器的穷尽¶ class Bank(): # lets create a bank, building ATMs
... crisis False
... def create_atm(self) :
... while not self.crisis :
... yield $100hsbc Bank() # when everythings ok the ATM gives you as much as you wantcorner_street_atm hsbc.create_atm()print(corner_street_atm.next())
$100print(corner_street_atm.next())
$100print([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.StopIterationwall_street_atm hsbc.create_atm() # its even true for new ATMsprint(wall_street_atm.next())
type exceptions.StopIterationhsbc.crisis False # trouble is, even post-crisis the ATM remains emptyprint(corner_street_atm.next())
type exceptions.StopIterationbrand_new_atm hsbc.create_atm() # build a new one to get back in businessfor cash in brand_new_atm :
... print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...对于控制一些资源的访问来说这很有用。
3.8. Itertools,你最好的朋友¶
itertools包含了很多特殊的迭代方法。是不是曾想过复制一个迭代器?串联两个迭代器把嵌套的列表分组不用创造一个新的列表的 zip/map?
只要 import itertools
需要个例子让我们看看比赛中4匹马可能到达终点的先后顺序的可能情况: horses [1, 2, 3, 4]races itertools.permutations(horses)print(races)
itertools.permutations object at 0xb754f1dcprint(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)]3.9. 了解迭代器的内部机理¶
迭代是一个实现可迭代对象(实现的是 __iter__() 方法)和迭代器(实现的是 __next__() 方法)的过程。可迭代对象是你可以从其获取到一个迭代器的任一对象。迭代器是那些允许你迭代可迭代对象的对象。
更多见这个文章 http://effbot.org/zone/python-for-statement.htm