轉(zhuǎn)自 http://lukejin.javaeye.com/blog/587051
前段時(shí)間在讀trac 中wiki模塊的源碼的時(shí)候,發(fā)現(xiàn)了很多地方都使用了yiled這一關(guān)鍵詞,
感覺是在需要返回某個(gè)值的地方通過yield來代替return,
不是很明白其用法,所以仔細(xì)研究下。
一個(gè)使用了yiled關(guān)鍵字的函數(shù)就不再是一個(gè)普通的函數(shù)了,而是一個(gè)生成器函數(shù)(generator function),
當(dāng)函數(shù)被調(diào)用的時(shí)候?qū)⒎祷匾粋€(gè)迭代器(iterator)。
所以下面將分別講解迭代器和生成器這兩個(gè)概念。
一. 迭代器(Iterator)
寫道
迭代器是一個(gè)對(duì)象,它實(shí)現(xiàn)了迭代器協(xié)議,
一般需要實(shí)現(xiàn)如下兩個(gè)方法
1)next方法
返回容器的下一個(gè)元素
2)__iter__方法
返回迭代器自身
對(duì)于for語言大家可能都不陌生,我們很多時(shí)候需要對(duì)一些容器對(duì)象進(jìn)行遍歷就會(huì)使用到for循環(huán):
- l=[0,1,2,3,4,5,6]
- for i in l:
- print i
l是一個(gè)type為list的對(duì)象,這段for-in代碼在運(yùn)行的時(shí)候其實(shí)是調(diào)用了l的__iter__()函數(shù),返回了一個(gè)實(shí)現(xiàn)了__next__()或next()(各個(gè)版本的python可能不一樣,我試驗(yàn)的時(shí)候所使用的版本為2.6.2)的迭代器對(duì)象,每循環(huán)一次就會(huì)通過next取下一個(gè)元素。
當(dāng)然我們完全沒有必要先把所有的元素都算出來放到一個(gè)list里或者其他容器類里進(jìn)行循環(huán),這樣比較浪費(fèi)空間。
我們可以直接創(chuàng)建自己的一個(gè)迭代器。
-
-
- ''
-
- class Fib:
- ''
-
- def __init__(self, max):
- self.max = max
-
- def __iter__(self):
- self.a = 0
- self.b = 1
- return self
-
- def next(self):
- fib = self.a
- if fib > self.max:
- raise StopIteration
- self.a, self.b = self.b, self.a + self.b
- return fib
定義好了這個(gè)Fibonacci迭代器,我們就可以來使用它了。
- from fibonacci2 import Fib
- for n in Fib(1000):
- print n
當(dāng)調(diào)用Fib(1000)的時(shí)候,將生成一個(gè)迭代器對(duì)象,每一次循環(huán)都將調(diào)用一次next取到下一個(gè)值。
所以我們可以看出迭代器有一個(gè)很核心的東西就是在循環(huán)中,迭代器可以記住之前的狀態(tài)。
二.生成器
前面我們說了,任何使用了yield關(guān)鍵字的函數(shù)都不再是普通的函數(shù)了,我們還是來看實(shí)例吧,這樣比較容易理解
- def fib(max):
- a, b = 0, 1
- while a < max:
- yield a
- a, b = b, a + b
這里簡(jiǎn)單的幾行代碼就實(shí)現(xiàn)了上面的迭代器類那么一大堆代碼所實(shí)現(xiàn)的功能
使用的時(shí)候和上面很類似:
- from fibonacci import fib
- for n in fib(1000):
- print n
引文fib函數(shù)使用了yield所以它是一個(gè)生成器函數(shù),當(dāng)我們調(diào)用fib(1000)的時(shí)候它其實(shí)是返回了一個(gè)迭代器,且這個(gè)迭代器可以控制生成器函數(shù)的運(yùn)行。
我們通過這個(gè)返回的迭代器的動(dòng)作控制fib這個(gè)生成器函數(shù)的運(yùn)行。
每當(dāng)調(diào)用一次迭代器的next函數(shù),生成器函數(shù)運(yùn)行到y(tǒng)ield之處,返回yield后面的值且在這個(gè)地方暫停,所有的狀態(tài)都會(huì)被保持住,直到下次next函數(shù)被調(diào)用,或者碰到異常循環(huán)退出。
所以生成器的概念還是很簡(jiǎn)單的。
三.總結(jié)
1.for-in語句在底層都是對(duì)一個(gè)迭代器對(duì)象進(jìn)行操作的
2.使用了yield關(guān)鍵字的函數(shù)就是一個(gè)生成器函數(shù),被調(diào)用的時(shí)候生成一個(gè)可以控制自己運(yùn)行的迭代器
實(shí)驗(yàn):
生成器并不是事先生成所有的結(jié)果,而是需要時(shí)生成
def fib(max):
a, b = 0, 1
while a < max:
yield a
print 'yield'
a, b = b, a+b
for n in fib(10):
print 'for'
print n
運(yùn)行結(jié)果
for
0
yield
for
1
yield
for
1
yield
for
2
yield
for
3
yield
for
5
yield
for
8
yield