[英]Weird behaviour of generator unpacking in Python
我目前正在嘗試更熟悉Python中的迭代器,我遇到了一些奇怪的行為。 從本質上講,我使用生成器理解得到了錯誤的行為,但是使用列表理解的正確行為。
首先讓我解釋一下我嘗試做什么,然后解釋我的行為。
想象一下,有一個可迭代的字典,例如
d = {'a': [1, 2, 3], 'b': [4, 5]}
我想要的是有一個字典列表,其中包含可迭代的所有可能組合。 對於第一個例子,這將是
l = [
{'a': 1, 'b': 4},
{'a': 1, 'b': 5},
{'a': 2, 'b': 4},
{'a': 2, 'b': 5},
{'a': 3, 'b': 4},
{'a': 3, 'b': 5},
]
為此,我創建了這個生成器:
def dict_value_iterator(d):
for k, v in d.items():
yield ((k, vi) for vi in v)
我們的想法是運行以下代碼來獲得想要的結果
def get_all_dicts(d):
return map(dict, *itertools.product(dict_value_iterator(d)))
現在,對於奇怪的行為。
為了測試dict_value_iterator
生成器確實做了我希望的那樣,我運行了以下代碼:
for i in dict_value_iterator(d):
print(list(i))
這確實做了我希望的,即打印出以下內容:
[('a', 1), ('a', 2), ('a', 3)]
[('b', 4), ('b', 5)]
但是,當我運行以下代碼時
def test_unpacking(*args):
for a in args:
print(list(a))
test_unpacking(*dict_value_iterator(d))
我得到了輸出
[('b', 1), ('b', 2), ('b', 3)]
[('b', 4), ('b', 5)]
這對我來說幾乎沒有任何意義,為什么迭代器解包會改變任何東西。
最后的說明。
我發現它的方法是在d上運行get_all_dicts
函數,這導致了以下輸出
[{'b': 4}, {'b': 5}, {'b': 4}, {'b': 5}, {'b': 4}, {'b': 5}]
但是,當我修改dict_value_iterator
如下
def dict_value_iterator(d):
for k, v in d.items():
yield ((k, vi) for vi in v)
我得到了這個輸出
[{'a': 1, 'b': 4},
{'a': 1, 'b': 5},
{'a': 2, 'b': 4},
{'a': 2, 'b': 5},
{'a': 3, 'b': 4},
{'a': 3, 'b': 5}]
這就是我想要的。
這是一個簡化版本:
generators = []
for i in [1, 2]:
generators.append((i for _ in [1]))
print(list(generators[0])) # [2]
只存在一個名為i
變量,而for
循環重復設置它。 由生成器表達式創建的所有生成器都引用相同的i
並且在循環退出之前不會讀取它。
修復它的一種方法是使用函數創建另一個范圍(例如,在ES5中):
def dict_value_iterator(d):
def get_generator(k, v):
return ((k, vi) for vi in v)
for k, v in d.items():
yield get_generator(k, v)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.