Понимание списка, который использует рекурсию - PullRequest
1 голос
/ 21 марта 2019

Я сейчас изучаю понимание списка и наткнулся на эту строку рекурсивного кода:

ans = [sort(a, i + 1) for a in ans]

Я попытался заменить эту строку следующим:

for a in ans:
    ans = (sort(a, i + 1))

Может ли кто-нибудь помочь мне понять, где я допустил ошибку?

спасибо!

1 Ответ

0 голосов
/ 24 марта 2019

Цикл for и понимание списка не эквивалентны.

Представьте, что у нас есть:

>>> def sort(a, _): return 2*a
...
>>> i=0

Тогда:

>>> ans=list(range(5))
>>> ans = [sort(a, i + 1) for a in ans]
>>> ans
[0, 2, 4, 6, 8]

Но:

>>> ans=list(range(5))
>>> for a in ans: ans=(sort(a, i+1))
>>> ans
8

Понимание списка в основном:

  • применяет sort(a, i+1) к каждому a в ans
  • , затем присваивает результат самой переменной ans.

Как сказал @chepner в комментарии, здесь нет рекурсии [1] .Это эквивалентно:

>>> ans=list(range(5))
>>> new_ans = [sort(a, i + 1) for a in ans]
>>> ans = new_ans
>>> new_ans
[0, 2, 4, 6, 8]

В то время как цикл for:

  • перебирает ans:
  • назначает sort(a, i+1) для ans для каждого a

Следовательно, назначения дают: ans = sort(ans[0], i+1), затем ans = sort(ans[1], i+1), ..., ans = sort(ans[-1], i+1), где ans[-1] - последний элемент оригинала ans2 .

Эквивалент цикла вашего понимания списка:

>>> ans=list(range(5))
>>> new_ans=[]
>>> for a in ans: new_ans.append(sort(a, i+1))
>>> ans = new_ans # assignement here
>>> ans
[0, 2, 4, 6, 8]

[1] Функция может использовать рекурсию, но я 'я не уверен, что рекурсия будет означать для понимания списка, если вы не используете грязный хак: для записи https://stackoverflow.com/a/221874/6914441.

[2] Обратите внимание, что переназначение переменной ans делаетне изменять исходный список:

  • при запуске цикла Python создает итератор над списком и сохраняет ссылку в списке;
  • при повторном воздействии на ansЦикл for по-прежнему содержит ссылку на исходный список.

Было бы иначе, если бы вы изменили список из тела цикла ( stronglу обескуражен ):

>>> xs=list(range(5))
>>> for x in xs: print(x, xs);_=xs.pop(0)
...
0 [0, 1, 2, 3, 4]
2 [1, 2, 3, 4]
4 [2, 3, 4]

Мы удаляем первый элемент для каждой итерации, но индекс продолжает расти:

[*0*, 1, 2, 3, 4] # then pop 0
[1, *2*, 3, 4] # then pop 1
[2, 3, *4*] # then pop 2
...