在 python 中咱們經常使用 for in 來遍歷 list, set, dict, str 等。
for in 的本質就幹了兩件事:python
咱們先了解幾個概念:算法
咱們先看看 Iterable 的實現ssh
from collections import Iterable help(Iterable) class Iterable(__builtin__.object) | Methods defined here: | | __iter__(self) | | ---------------------------------------------------------------------- | Class methods defined here: | | __subclasshook__(cls, C) from abc.ABCMeta | | ---------------------------------------------------------------------- | Data descriptors defined here: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | __abstractmethods__ = frozenset(['__iter__']) | | __metaclass__ = <class 'abc.ABCMeta'> | Metaclass for defining Abstract Base Classes (ABCs). | | Use this metaclass to create an ABC. An ABC can be subclassed | directly, and then acts as a mix-in class. You can also register | unrelated concrete classes (even built-in classes) and unrelated | ABCs as 'virtual subclasses' -- these and their descendants will
再看看 Iterator 的實現ide
from collections import Iterator help(Iterator) class Iterator(Iterable) | Method resolution order: | Iterator | Iterable | __builtin__.object | | Methods defined here: | | __iter__(self) | | next(self) | Return the next item from the iterator. When exhausted, raise StopIteration | | ---------------------------------------------------------------------- | Class methods defined here: | | __subclasshook__(cls, C) from abc.ABCMeta | | ---------------------------------------------------------------------- | Data and other attributes defined here: | | __abstractmethods__ = frozenset(['next']) | | ---------------------------------------------------------------------- | Data descriptors inherited from Iterable: | | __dict__ | dictionary for instance variables (if defined) | | __weakref__ | list of weak references to the object (if defined) | | ---------------------------------------------------------------------- | Data and other attributes inherited from Iterable: | | __metaclass__ = <class 'abc.ABCMeta'> | Metaclass for defining Abstract Base Classes (ABCs). | | Use this metaclass to create an ABC. An ABC can be subclassed | directly, and then acts as a mix-in class. You can also register | unrelated concrete classes (even built-in classes) and unrelated | ABCs as 'virtual subclasses' -- these and their descendants will | be considered subclasses of the registering ABC by the built-in | issubclass() function, but the registering ABC won't show up in | their MRO (Method Resolution Order) nor will method | implementations defined by the registering ABC be callable (not | even via super()).
從繼承關係來看,全部的 Iterator(迭代器)都是 Iterable(可迭代對象),
從實現角度看 Iterator 新增了 next() 方法。ui
from collections import Iterator, Iterable isinstance([1,], Iterator) // False isinstance((1,), Iterator) // False isinstance({}, Iterator) // False isinstance("abc", Iterator) // False isinstance(set([]), Iterator) // False isinstance([1,], Iterable) // True isinstance((1,), Iterable) // True isinstance({}, Iterable) // True isinstance("abc", Iterable) // True isinstance(set([]), Iterable) // True dir([]) // 沒有 next() 方法 dir([].__iter__()) // 有 next() 方法
將完了迭代器,咱們再說說生成器,這裏引用廖雪峯博客裏的介紹:this
經過列表生成式,咱們能夠直接建立一個列表。可是,受到內存限制,列表容量確定是有限的。
並且,建立一個包含100萬個元素的列表,不只佔用很大的存儲空間,
若是咱們僅僅須要訪問前面幾個元素,那後面絕大多數元素佔用的空間都白白浪費了。code
因此,若是列表元素能夠按照某種算法推算出來,那咱們是否能夠在循環的過程當中不斷推算出後續的元素呢?
這樣就沒必要建立完整的list,從而節省大量的空間。在Python中,這種一邊循環一邊計算的機制,
稱爲生成器(Generator)。協程
生成器的建立很簡單,能夠經過推導列表建立:對象
g = (x * x for x in range(10)) // 使用 [] 返回的是 list, () 返回的是 generator
還有一種方式是經過 yield 關鍵字生成。繼承
先看看生成器的實現:
<genexpr> = class generator(object) | Methods defined here: | | __getattribute__(...) | x.__getattribute__('name') <==> x.name | | __iter__(...) | x.__iter__() <==> iter(x) | | __repr__(...) | x.__repr__() <==> repr(x) | | close(...) | close() -> raise GeneratorExit inside generator. | | next(...) | x.next() -> the next value, or raise StopIteration | | send(...) | send(arg) -> send 'arg' into generator, | return next yielded value or raise StopIteration. | | throw(...) | throw(typ[,val[,tb]]) -> raise exception in generator, | return next yielded value or raise StopIteration. | | ---------------------------------------------------------------------- | Data descriptors defined here: | | gi_code | | gi_frame | | gi_running
能夠發現生成器較迭代器多了 send, throw 等方法。
這裏重點介紹下 send 方法,咱們知道在使用迭代器時,遇到 yield 關鍵字
會退出來,下一迭代時會繼續執行。先看個例子:
def MyGenerator(): value = yield 1 value = yield value gen = MyGenerator() print gen.next() // print 1 print gen.next() // print None
咱們看看具體執行過程:
修改下上面的例子:
def MyGenerator(): value = yield 1 value = yield value gen = MyGenerator() print gen.next() // print 1 print gen.send(2) // print 2
send 方法是指定的是上一次被掛起的yield語句的返回值,這麼說有點抽象,咱們看執行過程:
協程就是利用 yield 和生成器的 send() 方法實現的。