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

28 投票
2 回答
31758 浏览
提问于 2025-04-16 21:40

在我开始说话之前,先感谢这个社区,最近在这里我找到了很多编程问题的答案。就像那些赞美的话不需要用语言表达一样。总之,概率法则让我碰到了一个我用搜索框找不到的问题,所以我决定第一次明确地问一下。也许是我没有用足够“Python风”的词汇搜索,或者我就是不太会用谷歌/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环境中运行得很好。如果我忽略代码中常见的冗余部分,我发现生成器推导和生产者协程生成的生成器之间的映射很简单。作为一个务实的人,我尝试把同样的概念应用到字典上,因为字典推导已经存在,我想这两者应该是等价的:

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()

第一个可以运行,但第二个不行。它在第三行的冒号那里报了语法错误。

现在,要么是我在语法上稍微出错,要么是我对生产者协程的工作原理有很大的误解。我怀疑它失败的原因和你不能让协程返回一个列表而不是生成器是一样的,但我并不太确定。

所以,我其实就是在问怎么解决这个错误;提前谢谢你们。我更希望得到一个直接的答案,而不是给我一个全新的实现方法,但如果这是唯一的办法……

2 个回答

10

我想在一个Python函数中通过yield生成一个字典,所以找到了这个问题。下面是返回字典的代码。

def _f():
    yield 'key1', 10
    yield 'key2', 20

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

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

字典推导式的工作方式和列表/集合推导式以及生成器表达式是一样的。一个带有 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

撰写回答