PEP 288 – 生成器屬性與異常處理
- 作者:
- Raymond Hettinger <python at rcn.com>
- 狀態:
- 已撤回
- 類型:
- 標準軌跡 (Standards Track)
- 建立日期:
- 2002年3月21日
- Python 版本:
- 2.5
- 公告歷史:
摘要
本 PEP 提議透過提供拋出異常以及與運行中生成器共享數據的機制來增強生成器功能。
狀態
本 PEP 已撤回。異常拋出機制已擴展並併入 PEP 343。屬性傳遞功能未能吸引開發者,且缺乏明確的實現方式,也沒有能讓運行中的生成器存取其自身命名空間的簡潔方法。
原理
目前,只有基於類別(class)的迭代器才能提供屬性和異常處理。然而,基於類別的迭代器更難編寫、不夠精簡、可讀性較差且速度較慢。更好的解決方案是為生成器啟用這些功能。
啟用屬性賦值允許在運行中的生成器之間傳遞數據。使用屬性共享數據的方法在 Python 中隨處可見。雖然存在其他方法,但相比之下都顯得有些笨拙。
另一個演進步驟是增加一個生成器方法,允許將異常傳遞給生成器。目前,沒有簡潔的方法可以從生成器外部觸發異常。此外,生成器異常傳遞有助於緩解生成器中對 try/finally 的限制。對於需要在終止時刷新緩存或關閉資源的生成器來說,這種需求尤為迫切。
這兩項提議均向後相容,且不需要新的關鍵字。建議在 Python 2.5 版本中採用。
生成器屬性規範
本質上,該提議是模擬類別的屬性寫入。唯一的困難在於生成器缺乏引用自身實例的方法。因此,該提議是提供一個函數來尋找該引用。例如:
def mygen(filename):
self = sys.get_generator()
myfile = open(filename)
for line in myfile:
if len(line) < 10:
continue
self.pos = myfile.tell()
yield line.upper()
g = mygen('sample.txt')
line1 = g.next()
print 'Position', g.pos
生成器屬性的用途包括:
- 向生成器客戶端提供額外資訊(如上所示)。
- 外部設定控制生成器運行的標誌(例如告知生成器何時進入或跳過數據組)。
- 編寫具有複雜執行狀態的惰性消費者(例如算術編碼輸出流)。
- 編寫協程(如 Mertz 博士的文章 [1] 中所示)。
‘yield’ 和 ‘next’ 的控制流在此提案下保持不變。唯一的變化是數據可以與生成器相互傳遞。大部分底層機制已經就緒,只需添加訪問函數即可。
生成器異常傳遞規範
在生成器介面中加入 .throw(exception) 方法
def logger():
start = time.time()
log = []
try:
while True:
log.append(time.time() - start)
yield log[-1]
except WriteLog:
writelog(log)
g = logger()
for i in [10,20,40,80,160]:
testsuite(i)
g.next()
g.throw(WriteLog)
目前沒有現成的變通方法可以在生成器內部觸發異常。這是 Python 中唯一一處活動程式碼無法接收或傳遞異常的情況。
生成器異常傳遞也有助於解決生成器的一個固有限制,即禁止使用 try/finally 來觸發清理程式碼(PEP 255)。
註 A:選擇 throw 方法名稱有幾個原因。Raise 是關鍵字,因此不能用作方法名稱。與 raise 立即從當前執行點拋出異常不同,throw 會先返回生成器,然後再拋出異常。「throw」一詞暗示將異常放入另一個位置。此外,在其他語言中,throw 已與異常相關聯。
曾考慮過其他替代方法名:resolve()、signal()、genraise()、raiseinto() 和 flush()。沒有一個比 throw() 更合適。
註 B:為了保持 throw() 語法簡潔,僅支援 raise 語法的實例版本(不支援 “raise string” 或 “raise class, instance” 的變體)。
調用 g.throw(instance) 相當於在最近一次 yield 之後立即寫入 raise instance。
參考文獻
版權
此文件已歸入公有領域 (public domain)。
來源:https://github.com/python/peps/blob/main/peps/pep-0288.rst
最後修改日期:2025-02-01 08:55:40 GMT