1. 程式人生 > >【Python】使用生成器改寫直接返回列表的函式

【Python】使用生成器改寫直接返回列表的函式

本文是《Effect Python 編寫高質量Python程式碼的59個有效方法》的學習筆記。主要記錄生成器的使用方法和示例程式碼。

返回佇列的函式

如果函式要產生一系列結果,那麼最簡單的做法就是把這些結構都放在一份列表裡,然後將其返回給呼叫者。

def index_words(text):
    """用append方法將這些此的首字母索引新增到result列表中,並在函式結束時將其返回給呼叫者。"""
    result = []
    if text:
        result.append(0)
    for index, letter in enumerate(text):
        if
letter == ' ': result.append(index+1) return result

輸入一些測試值,驗證該函式能正常執行:

>address = 'Four score and seven years ago...'
result = index_words(address)
print(result[:3])

列印

[0, 5, 11]

生成器函式

這個函式改用生成器(generator)來寫會更好。生成器是使用yield表示式的函式。呼叫生成器函式時,它並不會真的執行,而是會返回迭代器。每次在這個迭代器上面呼叫內建的next

函式時,迭代器會把生成器推進到下一個yield表示式那裡。生成器傳給yield的每一個值,都會由迭代器返回給呼叫者。

def index_words_iter(text):
    if text:
        yield 0
    for index, letter in enumerate(text):
        if letter == ' ':
            yield index + 1
result = list(index_words_iter(address))

注意:生成器函式返回的迭代器是有狀態的,呼叫者不應該反覆使用。

由於迭代器只能產生一輪結果。在丟擲過StopIteration異常的迭代器或生成器上面繼續迭代第二輪,是不會有結果的。為解決此問題,我們可以明確地使用該迭代器製作一份列表,將它的全部內容都遍歷一次,並賦值到這份列表裡,然後就可以在複製出來的資料列表上面多次迭代了。

為類實現生成器

下面是一個可以迭代的容器類,用來從檔案中讀取每行資料。

class ReadFileLines(object):
    """
    可以迭代的容器類,從檔案中獲取資料
    """
    def __init__(self, path):
        self.path = path

    def __iter__(self):
        with open(self.path) as f:
            for line in f:
                yield line

多次迭代

如果想多次迭代生成器的資料,可以使用下面的函式。該函式會逐步拷貝生成器的所有資料,然後返回一個佇列資料。

def normalize_defensive(datas):
    """
    從生成器返回一份可以多次迭代的資料
    :param datas:容器 
    :return: result:佇列(list)
    """
    # 確保呼叫者傳進來的引數,並不是迭代器物件本身
    if iter(datas) is iter(datas):
        raise TypeError('Must supply a container')
    # TODO

    result = []
    for data in datas:
        # TODO

        result.append(data)

    return result