前面快速的学习了Python的基本操作,但是还是存在很多的问题,在特别是一些小的知识点很少关注,但是有非常的好用,yield是Python中比较有意思,也比较有难度,我也是阅读代码的过程中发现了这个函数的好处,yield是生成的意思,但是在python中则是作为生成器理解,生成器的用处主要可以迭代,这样简化了很多运算模型。
关于yield可以参看《Python 深入理解yield》这篇文章中比较详细的描述了yield的基本原理和问题。
yield在python2.5以后不再是一个句子,而是一个表达式,表达式是有返回值的,就如同我们在C语言中的if(expression)一样。
当函数中存在yield以后,那么该函数就不在是普通的函数了,而是一个生成器。当该函数被调用时,并不会自动执行,而是暂停中,可以从下面的代码中得到体现。
- >>> def mygenerator():
- ... print 'start....'
- ... yield 5
- ...
- >>> mygenerator()
- <generator object mygenerator at 0xa2084b4>
从上面的结果可以知道,在mygenerator()之后,并没有打印出starting....说明存在yield的函数被调用的时候是没有运行的,可以认为是暂停的状态,因此需要重新启动程序。这时采用next()即可实现函数的启动。
- >>> g = mygenerator()
- >>> g.next()
- start....
- 5
- >>> g.next()
- Traceback (most recent call last):
- File "", line 1, in <module>
- StopIteration
mygenerator()中创建了对象g,这时需要next()启动程序的运行,出现了上面的结果,也就是完成了程序的重新运行,但是遇到yield后就会再次停止,从上面的效果我们可以知道,在第一次运行g.next()之后,打印,然后遇到了yield 5,这时候就会停止,再次g.next()之后,后面没有yield,说明迭代过程结束,抛出了StopIteration异常。
- >>> def mygenerator2():
- ... print 'starting ....'
- ... yield 5
- ... print 'middle ....'
- ... yield 12
- ... print 'end ....'
- ...
- >>> g1 = mygenerator2()
- >>> g1.next()
- starting ....
- 5
- >>> g1.next()
- middle ....
- 12
- >>> g1.next()
- end ....
- Traceback (most recent call last):
- File "", line 1, in <module>
- StopIteration
上面的代码也说明我的分析是正确的,第一次调用next()就执行到yield 5,暂停,然后next(),重新启动,并执行到yield 12,然后再次next()之后就会抛出错误,从上面打印出来的字符串就可知道。但输出中我们还发现了5,12等这是为什么呢?我认为这实质上是yield 5的返回值,因为表达式也会存在值的问题,这是肯定会输出表达式的值。
那么这是否可以认为yield 5的返回值一定是5吗?实际上并不是这样,这个与send函数存在一定的关系,这个函数实质上与next()是相似的,区别是send是传递yield表达式的值进去,而next不能传递特定的值,只能传递None进去,因此可以认为g.next()和g.send(None)是相同的。
- >>> def mygenerator2():
- ... print 'starting ....'
- ... m = yield 5
- ... print m
- ... print 'middle ....'
- ... d = yield 12
- ... print d
- ... print 'end ....'
- ...
- >>> g1 = mygenerator2()
- >>> g1.next()
- starting ....
- 5
- >>> g1.send('pass expression')
- pass expression
- middle ....
- 12
- >>> g1.next()
- None
- end ....
- Traceback (most recent call last):
- File "", line 1, in <module>
- StopIteration
- >>> g1 = mygenerator2()
- >>> g1.next()
- starting ....
- 5
- >>> g1.send('pass expression')
- pass expression
- middle ....
- 12
- >>> g1.send('pass expression')
- pass expression
- end ....
- Traceback (most recent call last):
- File "", line 1, in <module>
- StopIteration
从上面的效果可知道,可以知道,next()的传递的实质上就是None,而send传递进来的pass expression也作为表达式yield n的返回值,因此我们可以知道,yield的返回值并不是n的值,而是和send()传递进去的参数密切相关。实质上yield n表达式的返回值是指上就是send()函数传递进去的参数,了解到这一点是非常重要的。
关于send()和next()函数的返回值也是需要我们详细去分析的,从下面的代码可以知道:
- >>> def returntest():
- ... m = yield 5
- ... print m
- ... n = yield 10
- ... print n
- ... h = yield 15
- ... print h
- ...
- >>> t = returntest()
- >>> n = t.next()
- >>> n
- 5
- >>> n = t.next()
- None
- >>> n
- 10
- >>> n = t.next()
- None
- >>> n
- 15
- >>> t = returntest()
- >>> n = t.next()
- >>> n
- 5
- >>> n = t.send(40)
- 40
- >>> n
- 10
- >>> n = t.send(50)
- 50
- >>> n
- 15
从上面的代码我们可以知道next()和send()的返回值是与yield n的n密切相关,实际上就是yield n的n值。而yield的返回值就是send()传递进来的非None参数。
有一段经典的代码是不得不去分析的:
- >>> def addlist(alist):
- ... for i in alist:
- ... yield i + 1
- ...
这段代码中实际上就是运用了上面几个函数的返回值,因为for ...in句式实质上就是一个迭代器,也就是说alist[i] = addlist.next(),采用next的返回值也就是yield n的参数值n,也就是完成了alist[i] = i+1.这就是返回值的灵活运用,这段代码被灵活的运用于Python的迭代器中。
总结:
yield 的返回值是send(参数)中的参数,比如send(10),那么yield的返回值就是10
send(None)和next()的意思是一样的,但是因为send不能传递None量,因此这才突显出了next()函数的作用,这两个函数的返回值通常就是yield n中的参数n。
存在yield的函数不是普通的函数,而是生成器,只有调用send()或者next()函数以后才能执行,否则就是暂停的形式,这与其他函数是存在差别的。
阅读(3995) | 评论(0) | 转发(1) |