簡體   English   中英

了解使用生成器理解中的產量之間的一些差異

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM