为什么在构造此 defaultdict 的每个循环期间不产生 return 个单独的值?
Why doesn't yield return individual values during each loop constructing this defaultdict?
这是原代码:
from collections import defaultdict
lis = [[1, 2], [2, 1], [3, 0], [2, 1], [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, 2), (2, 1), (3, 0)])
dict_items([(1, 2), (2, 2), (3, 0)])
dict_items([(1, 3), (2, 2), (3, 0)])
我想使用 yield
来获取这些印刷品。
from collections import defaultdict
li = [[1, 2], [2, 1], [3, 0], [2, 1], [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, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)])
嗯,找到问题了
因为defaultdict
是一个可变对象。
所以我需要复制 res
(不需要深度复制,因为项目是元组,是不可更改的)
from collections import defaultdict
from copy import copy
li = [[1, 2], [2, 1], [3, 0], [2, 1], [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)])
或者直接return.items()
from collections import defaultdict
from copy import copy
li = [[1, 2], [2, 1], [3, 0], [2, 1], [1, 1]]
def g(lis: list):
res = defaultdict(int)
for i, 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())
你自己的回答说的是真的。我只是想确保您明白,如果您将每个值收集到一个列表中,然后使用单个 print
语句打印该列表,那么您发现的这个事实对于您的第一个代码示例同样适用。 yield
与您遇到的问题无关。我希望您已经知道这一点,但我想指出这一点,以防稍后阅读本文的人可能认为这是使用 yield
引入的问题。不是。
要看到这一点,您可以更改第二个示例以立即打印产生的值。这样,您在两个示例中都在做同样的事情……在生成下一个值后立即打印它。如果这样做,两个版本的代码都会得到相同的结果。
这里有一组完整的代码来演示这一点:
from collections import defaultdict
lis = [[1, 2], [2, 1], [3, 0], [2, 1], [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, 2), (2, 1), (3, 0)])
dict_items([(1, 2), (2, 2), (3, 0)])
dict_items([(1, 3), (2, 2), (3, 0)])
dict_items([(1, 2)])
dict_items([(1, 2), (2, 1)])
dict_items([(1, 2), (2, 1), (3, 0)])
dict_items([(1, 2), (2, 2), (3, 0)])
dict_items([(1, 3), (2, 2), (3, 0)])
这是原代码:
from collections import defaultdict
lis = [[1, 2], [2, 1], [3, 0], [2, 1], [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, 2), (2, 1), (3, 0)])
dict_items([(1, 2), (2, 2), (3, 0)])
dict_items([(1, 3), (2, 2), (3, 0)])
我想使用 yield
来获取这些印刷品。
from collections import defaultdict
li = [[1, 2], [2, 1], [3, 0], [2, 1], [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, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)]) dict_items([(1, 3), (2, 2), (3, 0)])
嗯,找到问题了
因为defaultdict
是一个可变对象。
所以我需要复制 res
(不需要深度复制,因为项目是元组,是不可更改的)
from collections import defaultdict
from copy import copy
li = [[1, 2], [2, 1], [3, 0], [2, 1], [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)])
或者直接return.items()
from collections import defaultdict
from copy import copy
li = [[1, 2], [2, 1], [3, 0], [2, 1], [1, 1]]
def g(lis: list):
res = defaultdict(int)
for i, 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())
你自己的回答说的是真的。我只是想确保您明白,如果您将每个值收集到一个列表中,然后使用单个 print
语句打印该列表,那么您发现的这个事实对于您的第一个代码示例同样适用。 yield
与您遇到的问题无关。我希望您已经知道这一点,但我想指出这一点,以防稍后阅读本文的人可能认为这是使用 yield
引入的问题。不是。
要看到这一点,您可以更改第二个示例以立即打印产生的值。这样,您在两个示例中都在做同样的事情……在生成下一个值后立即打印它。如果这样做,两个版本的代码都会得到相同的结果。
这里有一组完整的代码来演示这一点:
from collections import defaultdict
lis = [[1, 2], [2, 1], [3, 0], [2, 1], [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, 2), (2, 1), (3, 0)])
dict_items([(1, 2), (2, 2), (3, 0)])
dict_items([(1, 3), (2, 2), (3, 0)])
dict_items([(1, 2)])
dict_items([(1, 2), (2, 1)])
dict_items([(1, 2), (2, 1), (3, 0)])
dict_items([(1, 2), (2, 2), (3, 0)])
dict_items([(1, 3), (2, 2), (3, 0)])