簡體   English   中英

Python中生成器解包的奇怪行為

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM