python3中的迭代器與產生器__python

來源:互聯網
上載者:User
迭代器(iterator)
def add(s, x): return s + xdef gen(): for i in range(4):  yield ibase = gen()for n in [1, 10]: base = (add(i, n) for i in base)print list(base)

這個東西輸出可以腦補一下, 結果是[20,21,22,23], 而不是[10, 11, 12, 13]。

要說產生器,必須首先說迭代器
區分iterable,iterator與itertion
講到迭代器,就需要區別幾個概念:iterable,iterator,itertion, 看著都差不多,其實不然。下面區分一下。

itertion: 就是迭代,一個接一個(one after another),是一個通用的概念,比如一個迴圈遍曆某個數組。
iterable: 這個是可迭代對象,屬於python的名詞,範圍也很廣,可重複迭代,滿足如下其中之一的都是iterable: 可以for迴圈: for i in iterable 可以按index索引的對象,也就是定義了getitem方法,比如list,str; 定義了iter方法。可以隨意返回。 可以調用iter(obj)的對象,並且返回一個iterator

iterator: 迭代器對象,也屬於python的名詞,只能迭代一次。需要滿足如下的迭代器協議 定義了iter方法,但是必須返回自身 定義了next方法,在python3.x是next。用來返回下一個值,並且當沒有資料了,拋出StopIteration可以保持當前的狀態

首先str和list是iterable 但不是iterator:

In [13]: si = iter(s)In [14]: siOut[14]: <iterator at 0x7f9453279dd0>In [15]: si.__iter__ # 有__iter__Out[15]: <method-wrapper '__iter__' of iterator object at 0x7f9453279dd0>In [16]: si.next #擁有nextOut[16]: <method-wrapper 'next' of iterator object at 0x7f9453279dd0>In [20]: si.__iter__() is si #__iter__返回自己Out[20]: TrueIn [1]: %pasteclass DataIter(object): def __init__(self, *args):  self.data = list(args)  self.ind = 0 def __iter__(self): #返回自身  return self def next(self): # 返回資料  if self.ind == len(self.data):   raise StopIteration  else:   data = self.data[self.ind]   self.ind += 1   return data## -- End pasted text --In [9]: d = DataIter(1,2)In [10]: for x in d: # 開始迭代 ....:  print x ....:12In [13]: d.next() # 只能迭代一次,再次使用則會拋異常---------------------------------------------------------------------------StopIteration        Traceback (most recent call last)----> 1 d.next()<ipython-input-1-c44abc1904d8> in next(self)  10  def next(self):  11   if self.ind == len(self.data):---> 12    raise StopIteration  13   else:  14    data = self.data[self.ind]

從next函數中只能向前取資料,一次取一個可以看出來,不過不能重複取資料,那這個可不可以解決呢。
我們知道iterator只能迭代一次,但是iterable對象則沒有這個限制,因此我們可以把iterator從資料中分離出來,分別定義一個iterable與iterator如下:

class Data(object): # 只是iterable:可迭代對象而不iterator:迭代器 def __init__(self, *args):  self.data = list(args) def __iter__(self): # 並沒有返回自身  return DataIterator(self)class DataIterator(object): # iterator: 迭代器 def __init__(self, data):  self.data = data.data  self.ind = 0 def __iter__(self):  return self def next(self):  if self.ind == len(self.data):   raise StopIteration  else:   data = self.data[self.ind]   self.ind += 1   return dataif __name__ == '__main__': d = Data(1, 2, 3) for x in d:  print x, for x in d:  print x,1,2,31,2,3

Python支援在容器上迭代,通過兩個方法實現,允許使用者自訂,序列總是支援迭代方法.

迭代器的功能可以使用列表代替,但如果有很多值,列表就會佔用太多的記憶體,而如果有可以一個接一個地計算值的函數,那麼就可以在使用時採用計算一個值時擷取一個值,佔用更少記憶體。 迭代器對於變數,有兩個方法iter(),next()

當遍曆一個迭代器的時候,它會修改內部狀態,導致你只能向前擷取下一個元素,不能通過迭代器訪問後面一個元素;也就是說當你通過迭代器訪問了一個元素以後,在當前迴圈中不能後退繼續訪問該元素了,除非你重新生產迭代器對象進行遍曆。

#迭代器對於變數list1=[1,2,3,4,5]it1=iter(list1)print(next(it1))print(next(it1))print('=============')for x in it1:    print(x, end='\n')print('=============')#可以使用next()函數list2=list('abcdefg')it2=iter(list2)while True:    try:        print(next(it2))    except StopIteration:        sys.exit()

輸出結果如下:

12=============345=============abcdefg
對於要返回迭代器的類,要實現iterator.iter(),iterator.next()

迭代器對象被要求支援下面的兩個方法,合起來形成迭代協議。

iterator._iter_()

返回迭代器對象自身。為了允許容器和迭代器被用於for和in語句中,必須實現該方法。

iterator._next_()
返回容器的下一個條目。如果沒有更多的條目,拋出StopIteration異常

另外需要注意的是在迭代器中next方法是return下一個元素的值,不像下面介紹的產生器yield一個元素

class Fibs:    def __init__(self):  # 初始化        self.a = 0        self.b = 1    def __next__(self):  # 擷取下一個條目        self.a, self.b = self.b, self.a + self.b        return self.a    def __iter__(self):  # 返回迭代器        return selffibs=Fibs()for f in fibs:    if f > 20:        break
產生器(generator)

任何使用yield的函數都稱之為產生器.

首先需要明確的就是產生器也是iterator迭代器,因為它遵循了迭代器協議.產生器函數跟普通函數只有一點不一樣,就是把 return 換成yield,其中yield是一個文法糖,內部實現了迭代器協議,同時保持狀態可以掛起。
(如果換成return 函數就返回了)

另外一種說法:產生器就是一個返回迭代器的函數,與普通函數的區別是產生器包含yield語句,更簡單點理解產生器就是一個迭代器。

使用yield,可以讓函數產生一個序列,該函數返回的物件類型是”generator”,通過該對象連續調用next()方法返回序列值。

產生器函數只有在調用_next()_方法的時候才開始執行函數裡面的語句.
在調用count函數時:c=count(7),並不會列印”counting”只有等到調用c.next()時才真正執行裡面的語句。每次調用next()方法時,count函數會運行到語句yield n處為止,next()的傳回值就是產生值n,此處為了查看傳回值列印了出來,可以去掉,再次調用next()方法時,函數繼續執行yield之後的語句(熟悉Java的朋友肯定知道Thread.yield()方法,作用是暫停當前線程的運行,讓其他線程執行),如:

yield作用就是返回一個產生器,它會儲存當前函數狀態,記錄下一次函數被調用next的時候運行狀態

a = (i for i in range(4))print(a)for i in a:    print(i)for i in a:    print('==')    print(i)只輸出0,1,2,3
def count(n):    print("cunting")    while n > 0:        print('before yield')        yield n  # 產生值:n        print(n)        n -= 1        print('after yield')c=count(7)c.__next__()#before yieldc.__next__()# 7# after yield# before yieldc.__next__()# 6# after yield# before yield

如果一直調用next方法,當執行到沒有可迭代的值後,程式就會報錯:

Traceback (most recent call last): File "", line 1, in StopIteration

所以一般不會手動的調用next方法,而使用for迴圈

for i in count(5):      print (i)
def fibonacci(n): # 產生器函數 - 斐波那契    a, b, counter = 0, 1, 0    while True:        if counter > n:            return        yield a        a, b = b, a + b        counter += 1# f 是一個迭代器,由產生器返回產生f = fibonacci(10)while True:    try:        print(next(f), end=" ")    except StopIteration:        sys.exit()
def fibonacci():    a=b=1    yield a    while True:        a,b = b,a+b        yield b# f=fibonacci()# print(type(fibonacci()))# f.__next__()# f.__next__()for num in fibonacci():    if num > 100:        break    print (num)    time.sleep(1)

可以調試看輸出,就明白了。

另外還有一種定義產生器的方法:產生器運算式”()”

my_generator = (x for x in range(3))print(type(my_generator))for i in my_generator:    print(i)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.