15.python的for循環與迭代器、生成器


  在前面學習講完while循環之后,現在終於要將for循環這個坑填上了。之所以拖到現在是因為for循環對前面講過的序列、字典、集合都是有效的,講完前面的內容再來講for循環會更加容易上手。

  首先,for循環和while循環一樣,都是在滿足一定條件的時候對其內層的代碼進行循環執行。不同的是,while循環判斷的是條件,而for判斷的是迭代對象。

    Python 中的 for 接受可迭代對象(例如序列或迭代器)作為其參數,每次迭代其中一個元素。

  我們先來看for循環的代碼:

a = (1, 2, 3, 4, 5)
for x in a:
    print x

 

  我們以序列中的元祖為例,發現其輸出了這些,那么這段代碼的邏輯是怎么樣的?為了方便大家理解,我畫了這樣一個圖:

  我寫了一個收租的小故事,方便大家理解。不知道為什么寫的時候感覺眼角有點濕潤。

  for循環其實就是不斷的去可迭代對象中拿去元素,而可迭代對象在每次迭代的時候都會把指針下移一格,也就是下次再來拿的時候,拿的是下一個。而這是因為可迭代對象有這樣行為,才稱其為可迭代。

  這個時候我又要問一個問題,在迭代循環結束以后,x的值是否還存在?

  當然還在,都說了作用域是函數的東西,迭代循環並不是函數。按照for循環的思路,x的值是不斷更新的,所以在循環結束的時候,x應該等於最后一次迭代的值。以這里為例,x在循環結束的時候,其值應該為5。即x=5。

a = (1, 2, 3, 4, 5)
for x in a:
    print x
print '----',x
print a

 

  

  另外,雖說交租是交了出去自己沒有了,但是迭代循環並不會改變a本身,也就是相當於借給別人看一眼,東西還是自己的。

  當然現實中沒有這樣的福利就是了。

  序列的迭代都和上面的一樣,其都是按照索引的順序依次給出。而字典和集合都是無序的,所以循環得到的順序和我們代碼寫的順序是不同的。但是我在字典篇中說過,字典的無序體現在其保存上,也就是一旦保存以后,其順序雖然和我們代碼寫的順序不同,但也不會每次循環得到的順序都不同。如果每次循環得到的順序都不同那要多大工程,浪費多少計算資源,這顯然不符合python化繁為簡的哲學。

   另外,這里提醒一句,字典循環得到的鍵,而集合沒有鍵的概念,所以得到的元素。

 


 

 1.迭代器和生成器

   你可能會看到這樣的寫法:

for x in range(1,5):
    print x

 

  range()是什么鬼,我們先進交換模式看一下先:

  

  直接返回了一個列表,也就是這個函數是快速生產列表的咯,for循環就相當於迭代了列表了咯,這就好理解了。

  還可能會有這個寫法:

for x in xrange(1,5):
    print x

   

  xrange()又是什么鬼?

  返回了自己。

  好吧,這里解釋一下,什么是迭代器和生成器了。


1.迭代器

  迭代器是一個實現了迭代器協議的對象,Python中的迭代器協議就是有next方法的對象會前進到下一結果,而在一系列結果的末尾是,則會引發StopIteration。

 

   而在for循環中,會自動調用 iter()將我們要迭代的對象轉化為可迭代對象,每次循環都會調用 .next() 方法獲取新元素,當引發StopIteration錯誤的時候自動退出循環,這就for循環的內部操作。

  常用的數據類型,如:str、tuple、list、dict、set,都能進行迭代循環,因為其內部都有相應的方法,如list中的:

  所以我們自己也可以創建一個可迭代的類:

class Text():
    def __init__(self,list_input):  #初始化函數
        self.list = list_input
        self.i = 0

    def __iter__(self):
        return self

    def next(self):
        if self.i == len(self.list):    #如果索引到了最后,說明迭代完畢
            self.i = 0  #將索引歸0
            raise StopIteration     #觸發錯誤
        #如果索引沒到最后
        self.i += 1 #索引先后移一位
        return self.list[self.i - 1]    #取出前一位的值

 

a = Text([1,2,3])
for x in a:
    print x

   這就是迭代器了。

 


2.生成器

  xrange()就是生成器。

  所謂的生成器就是每次調用的時候返回一個對象,而不是一次性在內存中創建,從而達到節約內存的作用。

  而生成器靠yield關鍵字實現,生成器的編寫類似於函數,只不過將函數的return改成了yield:

def scq():
    yield 1
    yield 2
    yield 3
a = scq()
print a.next()
print a.next()
print a.next()

  每次調用a.next()的時候得到的都是不同的值。

  當然我們也可以像函數一樣處理它:

  總之,yield的核心在於凍結函數,一旦遇到,凍結這個函數;而return在於結束函數,一旦遇到,返回結果,函數整個退出,下次調用時重新開始執行。

  當然,到了最后一個的時候也會觸發錯誤:

  可以看出,生成器是每次調用的時候生成一個對象,所以生成器比迭代器更節約內存,但也更耗費cpu,因為代碼需要運算。不過一般情況下,使用生成器會有更高的效率。

 


  最后補充range和xrange兩個函數的用法:

  range和xrange都接受三個參數:

  

  其中start和stop表示開始和結束,同樣不包括結束的那個值,后面的只是個分界線而已。當只給一個參數的時候,默認從0開始,即start=0。

  而step表示步長,和序列中的一樣,表示走幾步執行生成一次。

 


  暫時先寫這么多,后面有什么錯誤和補充的會繼續完善。

  參考和轉載的文獻:戳這里

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM