在前面學習講完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表示步長,和序列中的一樣,表示走幾步執行生成一次。
暫時先寫這么多,后面有什么錯誤和補充的會繼續完善。
參考和轉載的文獻:戳這里