簡體   English   中英

為什么Python具有最大遞歸深度?

[英]Why does Python have a maximum recursion depth?

Python具有最大遞歸深度,但沒有最大迭代深度。 為什么遞歸受限制? 像迭代這樣處理遞歸是不是更自然,而不是限制遞歸調用的數量?

我只想說這個問題的根源來自於嘗試實現一個流(有關流的更多詳細信息,請參閱此問題 )。 例如,假設我們要編寫一個流來生成自然數:

def stream_accum(s, n): # force the stream to a list of length n
    def loop(s, acc):
        if len(acc) == n:
            return acc
        hd, tl = s()
        return loop(tl, acc + [hd])
    return loop(s, [])


def nats():
    def loop(n):
        return n, lambda: loop(n+1)
    return loop(1)

流的遞歸定義非常吸引人。 但是,我想更好/更pythonic的方法是使用發電機。

這里實際上有一些問題。

首先,正如NPE的答案很好地解釋的那樣,Python並沒有消除尾調用,因此許多允許在Scheme中無限遞歸的函數在Python中是有限的。

其次,正如NPE所解釋的那樣,無法消除的調用會占用調用堆棧上的空間。 而且,即使在執行TCE的語言中,也有許多遞歸函數無法像迭代那樣對待。 (考慮遞歸調用自身兩次的天真Fibonacci函數。)

但是為什么調用堆棧首先是有限的資源? Python堆棧幀至少原則上可以在堆上實現並鏈接在一起(請參閱Stackless以獲得該原理的存在證明),並且在64位內存空間中,可以存儲超過1000個堆棧幀。 (實際上,即使是幾乎所有現代平台上的C堆棧都可以容納超過1000個遞歸Python解釋器調用。)

部分原因是歷史性的:股票Python解釋器使用固定的C堆棧在您進行遞歸調用時遞歸調用自身,並且它最初設計用於32位(甚至24位或20位)平台,其中C堆棧非常小。

但這可能已經改變了,Python 3.0將是一個改變它的完美場所。 那么,他們為什么不呢? 因為他們做出了有意識的語言設計決定。 在Pythonic代碼中,遞歸通常非常淺(例如,遍歷淺樹結構的os.walk代碼); 如果你的功能達到1000附近的任何深度,它更可能是一個錯誤,而不是故意的。 所以,限制仍然存在。 當然這有點循環 - 如果他們刪除了限制(特別是,如果他們消除了尾部調用),更深層次的遞歸將變得更加慣用。 但這就是重點 - 圭多不想要一種語言,其中深度遞歸是慣用的。 (並且大多數Python社區都同意。)

這不是Python獨有的,並且與調用堆棧上的每個調用占用空間有關,並且堆棧的大小是有限的。

單獨迭代不會消耗堆棧空間,因此不受此限制的約束。

並非每個遞歸調用都需要消耗堆棧空間。 例如,某些語言可以自動將尾遞歸轉換為迭代。 但是,CPython選擇不這樣做( Python會優化尾遞歸嗎? )。

您可以通過調用sys.setrecursionlimit來增加Python調用堆棧的最大深度。

遞歸需要調用堆棧上的空間,其大小有限。 使用過多級別的遞歸的代碼會產生一個稱為堆棧溢出的錯誤(也被一些不起眼的網站所熟知)。 Python似乎將此(有點任意)限制為1000級左右,但這可以通過設置sys.setrecursionlimit 來增加

迭代使用類似for -loop的東西,它通過遞增一些計數器並有條件地將指令指針設置回循環的開頭來實現。 這在記憶中是不變的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM