为什么在构建此 defaultdict 的每个循环期间 yield 不返回单个值?

问题描述

这是原始代码

from collections import defaultdict

lis = [[1,2],[2,1],[3,0],[1,1]]

res = defaultdict(int)
for i,j in lis:
    res[i] += j
    print(res.items())

结果

dict_items([(1,2)])
dict_items([(1,2),(2,1)])
dict_items([(1,1),(3,0)])
dict_items([(1,3),0)])

我想使用 yield获取这些印刷品。

from collections import defaultdict

li = [[1,1]]


def g(lis: list):
    res = defaultdict(int)
    for i,j in lis:
        res[i] += j
        yield res.items()


print(*g(li))

但我明白

dict_items([(1,0)]) dict_items([(1,0)])

解决方法

你在自己的回答中说的是真的。我只是想确保您了解,如果您将每个值收集到一个列表中,然后使用单个 print 语句打印该列表,那么您发现的这一事实同样适用于您的第一个代码示例。 yield 与您所看到的问题没有任何关系。我希望您已经知道这一点,但我想指出这一点,以防稍后阅读本文的人可能认为这是使用 yield 引入的问题。不是。

要看到这一点,您可以更改第二个示例以立即打印产生的值。这样,您在两个示例中都在做同样的事情……生成后立即打印下一个值。如果你这样做,你的代码的两个版本都会得到相同的结果。

这里有一套完整的代码来演示这一点:

from collections import defaultdict

lis = [[1,2],[2,1],[3,0],[1,1]]

res = defaultdict(int)
for i,j in lis:
    res[i] += j
    print(res.items())

def g(lis: list):
    res = defaultdict(int)
    for i,j in lis:
        res[i] += j
        yield res.items()

for v in g(lis):
    # Print the next generated value
    print(v)

结果:

dict_items([(1,2)])
dict_items([(1,2),(2,1)])
dict_items([(1,1),(3,0)])
dict_items([(1,3),0)])
,

好吧,我发现问题了。

因为 defaultdict 是一个可变对象。

所以我需要复制res(不需要深度复制,因为项目是元组,不可更改)

from collections import defaultdict
from copy import copy

li = [[1,1]]


def g(lis: list):
    res = defaultdict(int)
    for i,j in lis:
        res[i] += j
        yield copy(res)


print([x.items() for x in g(li)])

或者直接返回.items()

from collections import defaultdict
from copy import copy

li = [[1,j in lis:
        res[i] += j
        yield copy(list(res.items()))
        # reason to add list() is TypeError: cannot pickle 'dict_items' object


print(*g(li))

或者,使用list()来新建一个对象

def g(lis: list):
    res = defaultdict(int)
    for i,j in lis:
        res[i] += j
        yield list(res.items())