2009-12-07 66 views
2

這裏是一個函數(信用卡用戶住持,在另一個問題提供它)需要幫助理解這個遞歸函數是如何工作的

def traverse(ftp): 

    level = {} 
    for entry in (path for path in ftp.nlst() if path not in ('.', '..')): 
     ftp.cwd(entry) 
     level[entry] = traverse(ftp) 
     ftp.cwd('..') 
    return level 

這就是我不明白:當蟒蛇進入功能,它創建一個空字典(level)。在for循環中,它將目錄名稱作爲密鑰存儲在字典中。至於那個鍵的值,python再次輸入函數並搜索一個目錄,它就成爲該鍵的值。

但是,級別字典如何記住裏面的值?我的意思是,每當python進入函數時,它不應該被重置/清空嗎?

回答

7

否。該函數的每個「實例」都有自己的level副本,並且level的各個副本之間沒有副作用。

把這個文件夾樹:

root 
`-home 
    |- lyrae 
    | |- ftp.py 
    | `- http.py 
    `- badp 

這裏是(簡化)的執行流程,當你調用ftproot

  • ftp(root)創建一個空level詞典
  • ftp(root)枚舉子文件夾:(home)
  • ftp(root)選取第一個子文件夾並將目錄更改爲它。
  • ftp(root)level[home]設置爲當前文件夾中的ftp的結果。

  • ftp(home)創建一個空level詞典
  • ftp(home)枚舉子文件夾:(lyrae, badp)
  • ftp(home)選取第一個子文件夾並將目錄更改爲它。
  • ftp(home)level[lyrae]設置爲當前文件夾中的ftp的結果。

  • ftp(lyrae)創建一個空level詞典
  • ftp(lyrae)枚舉子文件夾:()
  • ftp(lyrae)不在子文件夾中解析並返回level

  • ftp(home)完成的任務:levels = {'lyrae': {}}
  • ftp(home)切換到下一個文件夾中。
  • ftp(home)level[badp]設置爲當前文件夾中ftp的結果。

  • ftp(badp)創建一個空level詞典
  • ftp(badp)枚舉子文件夾:()
  • ftp(badp)不在子文件夾中解析並返回level

  • ftp(home)完成的任務:levels = {'lyrae': {}, 'badp': {}}
  • ftp(home)超出子文件夾來解析,並返回level

  • ftp(root)完成的任務:levels = {'home': {'lyrae': {}, 'badp': {}}}
  • ftp(root)超出子文件夾來解析,並返回level
+0

所以只有當它'返回級別'這是否返回字典成爲父級的水平[條目]的值,是否正確? – sqram 2009-12-07 14:24:26

+1

這是正確的。 – badp 2009-12-07 14:30:57

+0

一個問題:(假設DIRB是DIRA dirB1和dirB2內部DIRB內)。在for循環,它抓住了DIRA目錄列表(返回DIRB)。然後進入dirB並找到dirB1和dirB2。它進入dirB1內部,找不到任何東西並返回到dirB。它現在進入dirB2。但是它怎麼知道進入dirB2?它會掃描dirB1並返回後DIRB,for循環將返回dirB1和dirB2。爲什麼不再進入dirB1? – sqram 2009-12-07 15:52:08

1

level是一個局部變量。函數的每個「運行」都有自己的變量level,因此這些變量不會相互干擾。

1

level的範圍僅限於功能。即使一個函數調用它本身,也並不意味着函數調用的內部變量(一個不同level)與這個一樣。

1

變量level只存在於一個函數的作用域內,在函數結束時局部變量被丟棄,所以每執行一次traverse就會有它自己的level字典。沒有什麼會被重寫或覆蓋。

+0

因此,每次函數調用自己時,都會創建一個新的等級= {},並保持原來的值不變?所以當它達到level [條目]時,它如何將該值添加到上一級的關鍵字? – sqram 2009-12-07 14:02:18

+0

爲什麼downvote? @lyrae:當你指定'traverse(ftp)' – SilentGhost 2009-12-07 14:19:08

+0

ah ok的結果時,它保存在父級別字典中。即時通訊仍然閱讀所有答案,試圖真正掌握這一點對不起,有人肯定會低估每個人。生病了upvote。 – sqram 2009-12-07 14:22:21

2

這些其他答案不足以解釋我足夠的理解。每個遞歸入口都會創建一個新的本地級字典。但關鍵的是,它也會返回它。這意味着來自每個遞歸的本地版本級別變成了級別的字典樹。一旦遞歸展開,你就剩下一棵互相引用的詞典樹。這意味着所創建的本地變量不會被垃圾收集,因爲從最外層的函數返回了堆棧中最頂層的字典的引用。