[英]Understanding some differences between using yield from generator comprehension
當我使用生成器理解實現解決方案時,我有一個行為與使用yield
關鍵字時不同的場景。
下面是兩個例子:
示例 A(這有效):
def get_latest_products(self) -> Generator:
first = True # avoid appending the CSV header (first row)
with open('path/to/my/file.csv')as file:
file = get_csv_reader(file)
for row in file:
if not first:
product = PageProduct(
page_name=row[0],
category_id=row[1],
product_id=row[2],
product_url=row[3],
product_name=row[4],
product_price=row[5],
)
yield product
first = False
示例 B(更優雅,如果沒有 I/O 處理也可以工作):
def get_latest_products(self) -> Generator:
with open('path/to/my/file.csv') as file:
file = get_csv_reader(file)
return (
PageProduct(
page_name=row[0],
category_id=row[1],
product_id=row[2],
product_url=row[3],
product_name=row[4],
product_price=row[5],
) for index, row in enumerate(file) if index > 0
)
當實現示例 B 時,我認為它更具可讀性和優雅性,我得到:(當我調用next()
時)
File "/Users/xxx/xxx/collect_products.py", line 157, in <genexpr>
return (
ValueError: I/O operation on closed file.
雖然示例 A 實現工作正常。 為什么?
您需要在with
語句的上下文中定義和使用生成器。 最好的方法是讓您的方法將可迭代(可能是文件句柄,也可能是其他東西)作為參數,而不是打開文件本身。
from itertools import islice
def get_latest_products(self, fh) -> Generator:
f = get_csv_reader(fh)
yield from (PageProduct(...) for row in islice(fh, 1, None))
從with
語句中調用方法:
with open('path/to/my/file.csv', r) as f:
for product in foo.get_latest_products(f):
...
這也使測試變得更加容易,因為您可以使用任何可迭代的方式調用get_latest_products
,而不是依賴文件系統中的文件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.