Python:在生成器中yield字典元素?

28

在我提出问题之前,先感谢社区成为我最近编程疑问的权威位置。就当那些赞美话没有被明确表达过。不管怎样,概率定律决定了我会碰到一些无法通过多功能搜索栏找到的内容,因此我决定第一次明确地发问。可能是因为我没有用足够 Pythonic 的术语进行搜索,或者我不擅长使用 Google/Stackoverflow 搜索。不管怎样……

我正在尝试使用 Python 协程和生成器。据我所知,使用生产者协程可以做到与生成器推导式相同的操作,只是更加冗长。我目前正在使用 Python 3,但任何关于 Python 2 的回答也都不会错过。

因此,我假设以下代码片段是等价的:

one_to_three = (num for num in range(1, 4))

...

def one_to_three():
    for num in range(1, 4):
        yield num

one_to_three_gen = one_to_three()

它在我的Python安装上运行良好。如果我忽略代码中常见的冗余特征,我会发现生成器推导式很容易映射到生产者协程生成的生成器上。作为务实的Pragmatic博士,我尝试将相同的概念映射到字典上,考虑到已经存在字典推导式,我认为这两个将是等价的:

one_to_three_doubles = {num : num * 2 for num in range(1, 4)}

...

def one_to_three_doubles():
    for num in range(1, 4):
        yield num : num * 2

one_to_three_doubles_gen = one_to_three_doubles()
第一个是起作用的,但第二个不行。它在第三行的冒号处标记了一个语法错误。
现在,要么我在语法上有很小的失误,要么我对生产者协同程序的工作原理有巨大的误解。我怀疑它失败的原因和你不能使协程返回列表而不是生成器是相同的,但我并不真正知道。
所以,是的,我基本上正在寻找解决那个错误的方法;提前谢谢。我更喜欢一个告诉我答案而不是给我一个全新的实现方式的答案,但如果这是唯一的方法...

你说的是生成器,而不是协程。如果你想了解协程是什么,请阅读《关于协程和并发的奇妙课程》(http://www.dabeaz.com/coroutines)。 - Jochen Ritzel
我认为有生产者和消费者协程,并且使用yielding模式创建序列是一种简单的协程用法,因为在每个值的yielding上执行暂停和恢复,这就是它跟踪位置的方式。不过,我的想法可能有误。 - Louis
2个回答

33

字典解析与列表/集合解析和生成器表达式的工作方式相同——"body"为expr for vars in iterable的X解析本质上等价于X(expr for vars in iterable)——并且您已经知道如何将生成器表达式转换为生成器。但请注意“几乎”这一点,因为直译不可行(正如您所注意到的那样),也完全没有必要(不会使实现更简单,而实际上可能会很繁琐)。

字典解析只是具有少量语法糖,以使其看起来更像字典文字(冒号)。从语义上讲,这并非必需——没有什么特别之处。停下来思考一下:字典解析必须在每次迭代中产生两个值,一个键和一个值。这正是冒号所代表的——(key, value)对(请记住dict接受(key, value)对的可迭代对象)。您无法在字典解析之外使用该语法糖,但可以使用元组代替这些对。因此,等价的生成器将是:

def one_to_three_doubles():
    for num in range(1, 4):
        yield num, num * 2

啊哈,这正是我想知道的;感谢您的及时回复。当您这样陈述时,它很有意义,并且当您提到dict接受一对可迭代对象时,它“恍然大悟”。 - Louis
4
使用dict(one_to_three_doubles())来创建一个字典。 - congusbongus
根据@congusbongus的评论,您还可以编写{k: v for k, v in one_to_three_doubles()}。这在您想要更改生成函数但不想更改生成的字典键或值时非常有用。 - QuantumChris

10
我想从 Python 函数的生成器表达式中生成一个字典,找到了这个问题。以下是返回字典的代码。
def _f():
    yield 'key1', 10
    yield 'key2', 20

def f(): return dict(_f())

print(f())
# Output:
{'key1': 10, 'key2': 20}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接