W rzeczywistości jest tu kilka problemów.
Po pierwsze, jak wyjaśnia NPE's answer, Python nie eliminuje wywołań końcowych, dlatego wiele funkcji, które pozwalają na nieograniczoną rekurencję w, powiedzmy, Schemacie są ograniczone w Pythonie.
Po drugie, zgodnie z wyjaśnieniami NPE, połączenia, których nie można wyeliminować, zajmują miejsce na stosie wywołań. I nawet w językach, które obsługują TCE, istnieje wiele funkcji rekursywnych, które nie mogą być traktowane jak iteracja. (Rozważmy naiwną funkcję Fibonacciego, która rekursywnie wywołuje się dwa razy.)
Ale dlaczego stos wywołajacy jest zasobem skończonym? Ramki stosów Pythona mogą co najmniej w zasadzie zostać zaimplementowane na stercie i połączone razem (patrz Stackless, aby uzyskać dowód istnienia tej zasady), a w 64-bitowej pamięci jest miejsce na dużo więcej niż 1000 klatek stosu. (W rzeczywistości, nawet stos C na prawie każdej nowoczesnej platformie może pomieścić znacznie więcej niż 1000 rekursywnych wywołań interpretera w języku Python).
Część przyczyn jest historyczna: giełdowy interpreter Pythona używa stałego stosu C, aby wywołać samą siebie rekurencyjnie za każdym razem, gdy wykonujesz rekursywne wywołanie, i został pierwotnie zaprojektowany dla platform 32-bitowych (a nawet 24- lub 20-bitowych), gdzie ten stos C jest dość mały.
Ale to mogło zostać zmienione, a Python 3.0 byłoby idealnym miejscem, aby to zmienić. Dlaczego więc nie? Ponieważ podjęli świadomą decyzję dotyczącą projektowania języka. W kodzie Pythonic rekursja jest generalnie bardzo płytka (np. Kod taki jak os.walk
, który trawi płytkie struktury drzewiaste); jeśli twoja funkcja osiąga głębokość w pobliżu 1000, jest bardziej prawdopodobne, że jest błędem, niż celowym. Limit zostaje. Oczywiście jest to nieco okrężne - jeśli usunęliby limit (a zwłaszcza, gdyby wyeliminowali ogony), głębsza rekurencja stałaby się bardziej idiomatyczna. Ale o to chodzi - Guido nie chce języka, w którym głęboka rekurencja jest idiomatyczna. (I większość społeczności Python się zgadza.)
"Atrakcyjne" rozwiązanie rekursywne ma wiele nieprzyjemnych aspektów. Po pierwsze, ma zachowanie O (n ** 2), ponieważ ciągle tworzysz nowe listy, aby je rozszerzyć. Po drugie, jest zbyt skomplikowany, biorąc pod uwagę, że możesz po prostu powtórzyć tworzenie liczb naturalnych. Jest to przykład pisania Pythona tak, jakby był Scheme lub Haskell. Różne języki są dobre w różnych rzeczach. Użyj iteracji. –