python基礎: 生成器,生成器表達式

能以一種一致的方式對序列進行迭代(比如列表中的對象或文件中的行)是Python的一個重要特點。這是通過一種叫做迭代器協議(iterator protocol,它是一種使對象可迭代的通用方式)的方式實現的。比如說,對字典進行迭代可以得到其所有的鍵:

>>> some_dict={'a':1,'b':2,'c':3}
>>> for key in some_dict:
...     print (key)
... 
a
b
c

當你編寫for key in some_dict時,Python解釋器首先會嘗試從some_dict創建一個迭代器:

>>> dict_iterator=iter(some_dict)
>>> dict_iterator
<dict_keyiterator object at 0x7f1674032048>

迭代器是一種特殊對象,它可以在諸如for循環之類的上下文中向Python解釋器輸送對象。大部分能接受列表之類的對象的方法也都可以接受任何可迭代對象。比如min、max、sum等內置方法以及list、tuple等類型構造器:

>>> list(dict_iterator)
['a', 'b', 'c']

生成器(generator)是構造新的可迭代對象的一種簡單方式。一般的函數執行之後只會返回單個值,而生成器則是以延遲的方式返回一個值序列,即每返回一個值之後暫停,直到下一個值被請求時再繼續。要創建一個生成器,只需將函數中的return替換爲yield即可:

def squares(n=10):
    for i in range(1,n+1):
        print("Generating squares from 1 to %d"%(n**2))
        yield i**2

調用該生成器時,沒有任何代碼會被立即執行:

>>> gen=squares()
>>> gen
<generator object squares at 0x7f166f7b6fc0>

直到你從該生成器中請求元素時,它纔會開始執行其代碼:

>>> for x in gen:
...     print(x)
... 
Generating squares from 1 to 100
1
Generating squares from 1 to 100
4
Generating squares from 1 to 100
9
Generating squares from 1 to 100
16
Generating squares from 1 to 100
25
Generating squares from 1 to 100
36
Generating squares from 1 to 100
49
Generating squares from 1 to 100
64
Generating squares from 1 to 100
81
Generating squares from 1 to 100
100

假設我們希望找出“將1美元(即100美分)兌換成任意一組硬幣”的所有唯一方式。你可能會想出很多種實現方法(包括“已找到的唯一組合”的保存方式)。下面我們編寫一個生成器來產生這樣的硬幣組合(硬幣面額用整數表示):

def make_change(amount,coins=[1,5,10,25],hand=None):
    hand=[] if hand is None else hand
    if amount==0:
        yield hand
    for coin in coins:
        # 確保我們給出的硬幣沒有超過總額,且組合是唯一的
        if coin>amount or (len(hand)>0 and hand[-1]<coin):
            continue
        for result in make_change(amount-coin,coins=coins,
                                  hand=hand+[coin]):
            yield result

這個算法的細節並不重要(你能想出更短點的辦法嗎?)。然後我們可以編寫:

>>> for way in make_change(100,coins=[10,25,50]):
...     print (way)
... 
[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]
[25, 25, 10, 10, 10, 10, 10]
[25, 25, 25, 25]
[50, 10, 10, 10, 10, 10]
[50, 25, 25]
[50, 50]

生成器表達式

生成器表達式(generator expression)是構造生成器的最簡單方式。生成器也有一個類似於列表、字典、集合推導式的東西,其創建方式爲,把列表推導式兩端的方括號改成圓括號:

>>> gen=(x**2 for x in range(100))
>>> gen
<generator object <genexpr> at 0x7f166f7b6f10>

它跟下面這個冗長得多的生成器是完全等價的:

def make_gen():
    for x in range(100):
        yield x**2
gen=make_gen()

生成器表達式可用於任何接受生成器的Python函數:

>>> sum(x**2 for x in range(100))
328350
>>> dict((i,i**2) for i in range(5))
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章