最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

python迭代器與生成器詳解

 更新時間:2016年03月10日 11:29:56   作者:shomy  
迭代器和生成器都是Python中特有的概念,迭代器可以看作是一個特殊的對象,每次調用該對象時會返回自身的下一個元素,從實現(xiàn)上來看,一個可迭代的對象必須是定義了__iter__()方法的對象,而一個迭代器必須是定義了__iter__()方法和next()方法的對象。

例子

老規(guī)矩,先上一個代碼:

def add(s, x):
 return s + x

def gen():
 for i in range(4):
  yield i

base = 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]。 當時糾結了半天,一直沒搞懂,后來齊老師稍微指點了一下, 突然想明白了--真夠笨的,唉。。好了--正好趁機會稍微小結一下python里面的生成器。

迭代器(iterator)

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

itertion: 就是迭代,一個接一個(one after another),是一個通用的概念,比如一個循環(huán)遍歷某個數(shù)組。
iterable: 這個是可迭代對象,屬于python的名詞,范圍也很廣,可重復迭代,滿足如下其中之一的都是iterable:
可以for循環(huán): for i in iterable
可以按index索引的對象,也就是定義了__getitem__方法,比如list,str;
定義了__iter__方法??梢噪S意返回。
可以調用iter(obj)的對象,并且返回一個iterator
iterator: 迭代器對象,也屬于python的名詞,只能迭代一次。需要滿足如下的迭代器協(xié)議
定義了__iter__方法,但是必須返回自身
定義了next方法,在python3.x是__next__。用來返回下一個值,并且當沒有數(shù)據了,拋出StopIteration
可以保持當前的狀態(tài)
首先str和list是iterable 但不是iterator:

In [3]: s = 'hi'

In [4]: s.__getitem__
Out[4]: <method-wrapper '__getitem__' of str object at 0x7f9457eed580>

In [5]: s.next # 沒有next方法
---------------------------------------------------------------------------
AttributeError       Traceback (most recent call last)
<ipython-input-5-136d3c11be25> in <module>()
----> 1 s.next

AttributeError: 'str' object has no attribute 'next'

In [6]: l = [1,2] # 同理

In [7]: l.__iter__
Out[7]: <method-wrapper '__iter__' of list object at 0x7f945328c320>

In [8]: l.next
---------------------------------------------------------------------------
AttributeError       Traceback (most recent call last)
<ipython-input-8-c6f8fb94c4cd> in <module>()
----> 1 l.next

AttributeError: 'list' object has no attribute 'next'
In [9]: iter(s) is s #iter() 沒有返回本身
Out[9]: False
In [10]: iter(l) is l #同理
Out[10]: False

但是對于iterator則不一樣如下, 另外iterable可以支持多次迭代,而iterator在多次next之后,再次調用就會拋異常,只可以迭代一次。

In [13]: si = iter(s)

In [14]: si
Out[14]: <iterator at 0x7f9453279dd0>

In [15]: si.__iter__ # 有__iter__
Out[15]: <method-wrapper '__iter__' of iterator object at 0x7f9453279dd0>

In [16]: si.next #擁有next
Out[16]: <method-wrapper 'next' of iterator object at 0x7f9453279dd0>

In [20]: si.__iter__() is si #__iter__返回自己
Out[20]: True

這樣,由這幾個例子可以解釋清楚這幾個概念的區(qū)別。

自定義iterator 與數(shù)據分離

說到這里,迭代器對象基本出來了。下面大致說一下,如何讓自定義的類的對象成為迭代器對象,其實就是定義__iter__和next方法:

In [1]: %paste
class DataIter(object):

 def __init__(self, *args):
  self.data = list(args)
  self.ind = 0

 def __iter__(self): #返回自身
  return self

 def next(self): # 返回數(shù)據
  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
 ....:
1
2

In [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函數(shù)中只能向前取數(shù)據,一次取一個可以看出來,不過不能重復取數(shù)據,那這個可不可以解決呢?

我們知道iterator只能迭代一次,但是iterable對象則沒有這個限制,因此我們可以把iterator從數(shù)據中分離出來,分別定義一個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 data

if __name__ == '__main__':
 d = Data(1, 2, 3)
 for x in d:
  print x,
 for x in d:
  print x,

輸出就是:

1,2,3
1,2,3
可以看出來數(shù)據可以復用,因為每次都返回一個DataIterator,但是數(shù)據卻可以這樣使用,這種實現(xiàn)方式很常見,比如xrange的實現(xiàn)便是這種數(shù)據與迭代分離的形式,但是很節(jié)省內存,如下:

In [8]: sys.getsizeof(range(1000000))
Out[8]: 8000072

In [9]: sys.getsizeof(xrange(1000000))
Out[9]: 40

另外有個小tips, 就是為什么可以使用for 迭代迭代器對象,原因就是for替我們做了next的活,以及接收StopIteration的處理。

迭代器大概就記錄到這里了,下面開始一個特殊的更加優(yōu)雅的迭代器: 生成器

生成器(generator)

首先需要明確的就是生成器也是iterator迭代器,因為它遵循了迭代器協(xié)議.

兩種創(chuàng)建方式

包含yield的函數(shù)

生成器函數(shù)跟普通函數(shù)只有一點不一樣,就是把 return 換成yield,其中yield是一個語法糖,內部實現(xiàn)了迭代器協(xié)議,同時保持狀態(tài)可以掛起。如下:

def gen():
 print 'begin: generator'
 i = 0
 while True:
  print 'before return ', i
  yield i
  i += 1
  print 'after return ', i

a = gen()

In [10]: a #只是返回一個對象
Out[10]: <generator object gen at 0x7f40c33adfa0>

In [11]: a.next() #開始執(zhí)行
begin: generator
before return 0
Out[11]: 0

In [12]: a.next()
after return 1
before return 1
Out[12]: 1

首先看到while True 不必驚慌,它只會一個一個的執(zhí)行~
看結果可以看出一點東西:

調用gen()并沒有真實執(zhí)行函數(shù),而是只是返回了一個生成器對象
執(zhí)行第一次a.next()時,才真正執(zhí)行函數(shù),執(zhí)行到y(tǒng)ield一個返回值,然后就會掛起,保持當前的名字空間等狀態(tài)。然后等待下一次的調用,從yield的下一行繼續(xù)執(zhí)行。
還有一種情況也會執(zhí)行生成器函數(shù),就是當檢索生成器的元素時,如list(generator), 說白了就是當需要數(shù)據的時候,才會執(zhí)行。

In [15]: def func():
 ....:  print 'begin'
 ....:  for i in range(4):
 ....:   yield i

In [16]: a = func()

In [17]: list(a) #檢索數(shù)據,開始執(zhí)行
begin
Out[17]: [0, 1, 2, 3]

yield還有其他高級應用,后面再慢慢學習。

生成器表達式

列表生成器十分方便:如下,求10以內的奇數(shù):
[i  for i in range(10) if i % 2]

同樣在python 2.4也引入了生成器表達式,而且形式非常類似,就是把[]換成了().

In [18]: a = ( i for i in range(4))

In [19]: a
Out[19]: <generator object <genexpr> at 0x7f40c2cfe410>

In [20]: a.next()
Out[20]: 0

可以看出生成器表達式創(chuàng)建了一個生成器,而且生有個特點就是惰性計算, 只有在被檢索時候,才會被賦值。
之前有篇文章:python 默認參數(shù)問題及一個應用,最后有一個例子:

def multipliers():
 return (lambda x : i * x for i in range(4)) #修改成生成器
print [m(2) for m in multipliers()]

這個就是說,只有在執(zhí)行m(2)的時候,生成器表達式里面的for才會開始從0循環(huán),然后接著才是i * x,因此不存在那篇文章中的問題。

惰性計算這個特點很有用,上述就是一個應用,2gua這樣說的:

性計算想像成水龍頭,需要的時候打開,接完水了關掉,這時候數(shù)據流就暫停了,再需要的時候再打開水龍頭,這時候數(shù)據仍是接著輸出,不需要從頭開始循環(huán)
其實本質跟迭代器差不多,不一次性把數(shù)據都那過來,需要的時候,才拿。

回到例子

看到這里,開始的例子應該大概可以有點清晰了,核心語句就是:

for n in [1, 10]:
 base = (add(i, n) for i in base)

在執(zhí)行l(wèi)ist(base)的時候,開始檢索,然后生成器開始運算了。關鍵是,這個循環(huán)次數(shù)是2,也就是說,有兩次生成器表達式的過程。必須牢牢把握住這一點。

生成器返回去開始運算,n = 10而不是1沒問題吧,這個在上面提到的文章中已經提到了,就是add(i, n)綁定的是n這個變量,而不是它當時的數(shù)值。

然后首先是第一次生成器表達式的執(zhí)行過程:base = (10 + 0, 10 + 1, 10 + 2, 10 +3),這是第一次循環(huán)的結果(形象表示,其實已經計算出來了(10,11,12,3)),然后第二次,base = (10 + 10, 11 + 10, 12 + 10, 13 + 10) ,終于得到結果了[20, 21, 22, 23].

具體執(zhí)行過程可以在pythontutor上手動看看執(zhí)行過程。

小結

概括
主要介紹了大概這樣幾點:

1.iterable,iterator與itertion的概念
2.迭代器協(xié)議
     自定義可迭代對象與迭代器分離,保證數(shù)據復用
3.生成器: 特殊的迭代器,內部實現(xiàn)了迭代器協(xié)議

其實這一塊, 那幾個概念搞清楚, ,這個很關鍵, 搞懂了后面就水到渠成了。而且對之前的知識也有很多加深。
比如常見list就是iterator與iteable分離實現(xiàn)的,本身是可迭代對象,但不是迭代器, 類似與xrange,但是又不同。
越來越明白,看源碼的重要性了。 有地方寫的不合適的, 請指正。

參考

http://www.shutupandship.com/2012/01/understanding-python-iterables-and.html
http://www.learningpython.com/2009/02/23/iterators-iterables-and-generators-oh-my/
http://stackoverflow.com/questions/9884132/what-exactly-are-pythons-iterator-iterable-and-iteration-protocols
http://python.jobbole.com/81881/

相關文章

  • Python實現(xiàn)最大子序和的方法示例

    Python實現(xiàn)最大子序和的方法示例

    這篇文章主要介紹了Python實現(xiàn)最大子序和的方法示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-07-07
  • python try 異常處理(史上最全)

    python try 異常處理(史上最全)

    為了處理異常,我們使用try...except,這篇文章主要介紹了python try 異常處理,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-03-03
  • python的ArgumentParser使用及說明

    python的ArgumentParser使用及說明

    這篇文章主要介紹了python的ArgumentParser使用及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Python CSV文件模塊的使用案例分析

    Python CSV文件模塊的使用案例分析

    這篇文章主要介紹了Python CSV文件模塊的使用,結合具體案例形式分析了Python使用csv模塊操作csv文件的相關使用技巧與相關注意事項,需要的朋友可以參考下
    2019-12-12
  • matplotlib階梯圖的實現(xiàn)(step())

    matplotlib階梯圖的實現(xiàn)(step())

    這篇文章主要介紹了matplotlib階梯圖的實現(xiàn)(step()),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-03-03
  • python+selenium實現(xiàn)QQ郵箱自動發(fā)送功能

    python+selenium實現(xiàn)QQ郵箱自動發(fā)送功能

    這篇文章主要為大家詳細介紹了python+selenium實現(xiàn)QQ郵箱自動發(fā)送功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • Python模擬隨機游走圖形效果示例

    Python模擬隨機游走圖形效果示例

    這篇文章主要介紹了Python模擬隨機游走圖形效果,涉及Python隨機數(shù)概率運算及圖形繪制相關操作技巧,需要的朋友可以參考下
    2018-02-02
  • Django 多對多字段的更新和插入數(shù)據實例

    Django 多對多字段的更新和插入數(shù)據實例

    這篇文章主要介紹了Django 多對多字段的更新和插入數(shù)據實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-03-03
  • 科學計算NumPy之Ndarray運算函數(shù)操作示例匯總

    科學計算NumPy之Ndarray運算函數(shù)操作示例匯總

    這篇文章主要為大家介紹了科學計算NumPy之Ndarray運算函數(shù)操作示例匯總,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • 用Python操作字符串之rindex()方法的使用

    用Python操作字符串之rindex()方法的使用

    這篇文章主要介紹了用Python操作字符串之rindex()方法的使用,是Python入門的基礎知識,需要的朋友可以參考下
    2015-05-05

最新評論

晋城| 黄梅县| 团风县| 雷波县| 寿阳县| 青龙| 阳城县| 社会| 新宾| 宁城县| 四川省| 辽宁省| 龙州县| 清水河县| 华宁县| 乐东| 泗阳县| 江川县| 乳源| 法库县| 如皋市| 远安县| 镇康县| 湾仔区| 林周县| 三亚市| 岳池县| 郑州市| 独山县| 丰都县| 无为县| 怀宁县| 绥滨县| 济南市| 古丈县| 石首市| 西城区| 师宗县| 汝南县| 共和县| 尉氏县|