要判斷一個Pythonista編寫的代碼夠不夠pythonic,一個很重要的標準就是看他能不能靈活運用迭代器。
首先要介紹一下什麼是迭代器:在python中有兩種循環語句,while和for。通常我們可以以c風格來使用它們,但是python額外提供了另外一種更爲方便和高效的使用方式。通俗的來說就是邊生產邊消費。代碼易讀性和簡潔高效性之爭
首先要介紹一下幾個概念之間得差異:
-
可迭代對象: 除了列表、元組、字符串、元組、集合、字典等序列外,只要實現了__iter__和__getitem__中任意一個方法的對象都是可以進行迭代的。不同的是,在進行迭代的時候解釋器會調用iter函數,iter函數會檢查對象是否實現了__iter__方法,如果實現了就會調用它得到一個生成器,如果沒有實現__iter__方法但是實現了 __getitem__方法,Python 會創建一個迭代器, 嘗試按順序(從索引 0 開始) 獲取元素。isinstance(objiect, Iterable)只會檢測__iter__方法,忽略了__getitem__方法。
# coding=utf8 from collections import Iterable list_a = [3, 3, 45, 6] dict_b = {'a': 'ji', 'b': 'ok', 'c': 'illegall'} set_c = {'df', 'fdk', 'lo'} tuple_d = ('jfk', 'dj', 'ilsl') str_e = 'jkilljls' isinstance(list_a, Iterable) # True 列表是可迭代對象 isinstance(dict_b, Iterable) # True 字典是可迭代對象 isinstance(set_c, Iterable) # True 集合是可迭代對象 isinstance(tuple_d, Iterable) # True 元組是可迭代對象 isinstance(str_e, Iterable) # True 字符串是可迭代對象
class Queue: def __init__(self, q): self.queue = q def __iter__(self): for item in self.queue: yield item # def __getitem__(self, item): # return self.queue[item] queue = Queue([1, 4, 5, 8]) print(isinstance(queue, Iterable)) #True 只要實現了__iter__方法則該對象就是可迭代對象,還有其他情況見後面
class Queue: def __init__(self, q): self.queue = q #def __iter__(self): # for item in self.queue: # yield item def __getitem__(self, item): return self.queue[item] queue = Queue([1, 4, 5, 8]) isinstance(queue, Iterable) #False 沒有實現__iter__方法,但是實現了__getitem__方法也是可迭代對象 #Iterable只對__iter__方法進行檢測 for item in queue: # 只要實現了__iter__和__getitem__中的任意一個,則該對象都是可以進行迭代的。 print(item)
-
迭代器: 實現了next方法和__iter__方法的對象,且next方法實現了迭代協議,__iter__方法返回迭代器。
如下是一個迭代器類,可以產生迭代器對象,對迭代器對象調用iter函數返回迭代器類自身,迭代環境中自動調用__next__方法。class iter: def __init__(self, data): self.data = data self.now = 0 def __iter__(self): return self def __next__(self): if self.now < data: self.now += 1 return (self.now-1)**2 raise StopIteration
-
生成器:生成器是一種特殊的迭代器,生成器自動實現了“迭代器協議”(即__iter__和next方法),不需要再手動實現兩方法。
3.1 生成器表達式:可以使用表達式來得到生成器
使用生成器表達式可以非常輕鬆的得到生成器,只要將列表解析式中的方括號換成圓括號就可以了。(x for x in range(5)) # iterator
3.2 生成器函數:在函數中使用關鍵詞yield得到生成器
def gen(num): cou = 0 while cou < num: yield cou cou += 1