#python
Вопрос:
Что-то, чего я не понимаю, происходит, когда я пытаюсь преобразовать итератор, возвращаемый yield
в список.
Например, 1:
def test(n): params = dict() for i in range(n): params[i] = i yield params for item in test(10): print(item)
Все выходы в порядке:
{0: 0} {0: 0, 1: 1} {0: 0, 1: 1, 2: 2} ... ... {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8} {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
Но с примером 2:
~ # same as above def test(n): params = dict() for i in range(n): params[i] = i yield params test_lst = list(test(10)) # change here for item in test_lst: # ~ print(item)
Случилось то, чего я не ожидал:
{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9} ... ... {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}
Так может ли кто-нибудь сказать мне, почему?
Ответ №1:
Вашу проблему можно свести к следующему:
Почему print
дает мне увеличивающиеся шаги объекта, в то время list
как дает мне все конечные точки?
Ответ, если потому, что ваш test_lst содержит указатели на один и тот же объект, и этот объект обновлялся с течением времени, пока печать показывала вам снимок объекта.
Если вам нужны промежуточные шаги, вам нужно сделать копию:
[i.copy() for i in test(4)]
выход:
[{0: 0}, {0: 0, 1: 1}, {0: 0, 1: 1, 2: 2}, {0: 0, 1: 1, 2: 2, 3: 3}]
указатель на один и тот же объект:
[i for i in test(4)]
[{0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}]
Еще один способ понять проблему. Попробуйте изменить (не заменить) один из элементов в списке:
gt;gt;gt; test_lst[0][0] = 'abc' [{0: 'abc', 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, {0: 'abc', 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, {0: 'abc', 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}, {0: 'abc', 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9}]
Ответ №2:
Когда вы вызываете list
функцию на своем итераторе, она повторяет всю коллекцию до тех пор, пока она не будет исчерпана. Таким образом, вы сразу получаете все возможные значения.
К счастью, ваш генератор не бесконечен 🙂
Комментарии:
1. Нет, вопрос в том, почему печать и список дают разные результаты. Тот факт, что генератор конечен, является предварительным условием кода, а не источником проблемы.
2. @mozway В обоих случаях пользователь повторяет результат и печатает элемент каждую итерацию. Вопрос не в печати, а в форме элементов в коллекции после приведения к а
list
.3. @mozway ваш ответ интересен, но я искренне думаю, что вопрос касался поведения генератора.
4. Я думаю, что вопрос в том, почему первое создание списка «дает» (каламбур) другой результат, чем при прямой итерации, используя только
for
цикл. И вы оба правы, оба ответа верны, на мой взгляд, хотя и с разными формулировками. Совет для ЕгорЛу: Я думаю, что этот ответ немного короток и труден для понимания тем, кто еще не знаком с этими темами (поэтому любой, кто задаст вышеуказанный вопрос). Некоторые дополнительные объяснения и/или пример могут улучшить ответ.5. Я чувствую, что оба ответа полезны тем, что они объясняют проблему с разных точек зрения / уровней детализации. Голосуйте за обоих.