您好,登錄后才能下訂單哦!
小編給大家分享一下Python怎么在遞歸函數(shù)中使用迭代器,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
首先,想要實(shí)現(xiàn)的功能是遞歸遍歷文件夾,遇到滿足條件的文件時,用yield返回該文件的位置。
如果不用遞歸器,可以這樣實(shí)現(xiàn):
path_list = [] def get_one_cage(root: str, cook_folder_name: str): for item in os.listdir(root).copy(): item_path = os.path.join(root, item) if item == cook_folder_name: path_list.append(item_path) return elif os.path.isdir(item_path): get_one_cage(item_path, cook_folder_name)
即,深度優(yōu)先遍歷,滿足要求時,將item_path補(bǔ)充到列表里,之后返回上一層。
這里有一個問題,需要有一個列表,把所有滿足條件的地址全存起來,占內(nèi)存。
使用迭代器可以用一個,遍歷出來一個,省內(nèi)存
替換為迭代器,最先想到的是,把 return 換成 yield,使用for循環(huán)調(diào)用迭代器函數(shù)
def get_one_cage(root: str, cook_folder_name: str): for item in os.listdir(root).copy(): item_path = os.path.join(root, item) if item == cook_folder_name: yield item_path elif os.path.isdir(item_path): get_one_cage(item_path, cook_folder_name)
但是這樣的程序跑到內(nèi)嵌函數(shù)時,進(jìn)不去,我百思不得其解
現(xiàn)在看,應(yīng)該是因?yàn)榈骱瘮?shù)不是一個函數(shù),不是一個命令語句,它只是一個對象。
簡單說就是,python程序一般遵循:動詞+名詞的結(jié)構(gòu),或者動詞,比如:
a = 1
這句話實(shí)際上是把1賦值給了a,是有動詞的。
迭代器只是一個名詞,必須用for語句調(diào)用或者next()方法調(diào)用才會執(zhí)行,或者是print,yield,return等等,反正得加個動詞,不能孤零零一個名詞。
而且上述代碼還有一個漏洞。在第一段代碼中,我們用一個全局變量存放遍歷結(jié)果。在第二段代碼里,我們本意是把結(jié)果yield到for循環(huán)調(diào)用的地方,但事實(shí)是,程序已經(jīng)套了好幾層了,每次yiled只能返回一層。如下圖所示:
綜上兩點(diǎn)作出如下修改:
def get_one_cage(root: str, cook_folder_name: str): for item in os.listdir(root).copy(): item_path = os.path.join(root, item) if item == cook_folder_name: yield item_path elif os.path.isdir(item_path): yield get_one_cage(item_path, cook_folder_name)
程序執(zhí)行結(jié)果如下:
顯然是返回了一個迭代器,不是一個str,其邏輯如下圖所示:
就好比,本意是:
小明把沙袋傳給小紅,小紅傳給小蘭
但現(xiàn)在是:
小明把沙袋傳給了小紅,小紅被傳了出去
修改如下:
def get_one_cage(root: str, cook_folder_name: str): for item in os.listdir(root).copy(): item_path = os.path.join(root, item) if item == cook_folder_name: yield item_path elif os.path.isdir(item_path): yield next(get_one_cage(item_path, cook_folder_name))
邏輯如下:
還有一種情況是學(xué)長源碼里的:使用for調(diào)用迭代器:
def get_one_cage(root: str, cook_folder_name: str): for item in os.listdir(root).copy(): item_path = os.path.join(root, item) if item == cook_folder_name: yield item_path elif os.path.isdir(item_path): for i in get_one_cage(item_path, cook_folder_name): yield i
這使用于多個文件的返回,源碼里還配合isfile使用,這里是簡化版,所以顯得冗余。
兩種方式均可以正常使用。
昨天這篇文章寫完后,遇到了bug,簡單說就是,如果一個文件夾系統(tǒng)沒有我們想要的文件,遞歸到最深一層文件夾時,會報(bào)錯
1
可以理解為:老板讓員工找一樣?xùn)|西,員工外包給編外人員。如果編外人員找到了想要的東西,一路傳遞回去,可以正常交差。如果沒找到,編外人員就會一直找,不停歇,找遍了所有能找到的地方(遍歷完整個文件夾)也沒能找到,就會報(bào)錯StopIteration。
因此,問題核心是,沒有一個返回機(jī)制。修改辦法是在遍歷最后加一個空返回
def get_one_cage(root: str): for index, item in enumerate(os.listdir(root)): item_path = os.path.join(root, item) if item == 'cooked_xyz': yield item_path elif os.path.isdir(item_path): yield next(get_one_cage(item_path)) elif index == len(os.listdir(root).copy()) - 1: yield
或者是利用try… except語句處理異常:
def get_one_cage(root: str): try: for item in os.listdir(root): item_path = os.path.join(root, item) if item == 'cooked_xyz': yield item_path elif os.path.isdir(item_path): yield next(get_one_cage(item_path)) except: yield
會有如上報(bào)錯,正常。
最后的yield換成return也是可以的,但最好還是用yield,兩個混起來用怪怪的。
個人推薦第二種方法
注:copy()可以不用要
以上是“Python怎么在遞歸函數(shù)中使用迭代器”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。