Выход в Python

#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. Я чувствую, что оба ответа полезны тем, что они объясняют проблему с разных точек зрения / уровней детализации. Голосуйте за обоих.