【Python】使用生成器改寫直接返回列表的函式
阿新 • • 發佈:2019-01-06
本文是《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