В настоящее время я пытаюсь лучше познакомиться с итераторами в 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)]
Для меня это мало что значит, почему распаковка итератора что-то меняет.
Последнее замечание.
Я нашел это, запустив функцию get_all_dicts
для d, что привело к следующему выводу
[{'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}]
, который я и хочу.