鱼C论坛

 找回密码
 立即注册
查看: 7630|回复: 27

遍历文件递归调用后返回上一层目录的疑问

[复制链接]
发表于 2016-12-9 17:01:22 | 显示全部楼层 |阅读模式
10鱼币
python第30讲课后作业第二题【在指定路径里搜索指定名字的文件,如遇文件夹,则进入文件夹继续搜索】,小甲鱼老师给出的答案里,递归调用后必须要返回上一层,代码如下:
import os

def search_file(start_dir, target) :
    os.chdir(start_dir)
   
    for each_file in os.listdir(os.curdir) :
        if each_file == target :
            print(os.getcwd() + os.sep + each_file) # 使用os.sep是程序更标准
        if os.path.isdir(each_file) :
            search_file(each_file, target) # 递归调用
            os.chdir(os.pardir) # 递归调用后切记返回上一层目录

start_dir = input('请输入待查找的初始目录:')
target = input('请输入需要查找的目标文件:')
search_file(start_dir, target)


这里不明白为什么要返回上一层,我觉得这条语句是永远不会被执行的,实际测试中把这条注释掉也是可以得出正确结果的,这个问题耗费了我一天去求解,现在还是没有一个明确的答案,哪位大神能提点一下,万分感谢!



想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-12-9 17:05:35 | 显示全部楼层
看你的目录结构

评分

参与人数 1荣誉 +3 鱼币 +3 贡献 +2 收起 理由
fujia1943 + 3 + 3 + 2

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-12-9 17:32:29 | 显示全部楼层
def search_file(start_dir, target) :
    os.chdir(start_dir)
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-12-10 20:02:16 | 显示全部楼层
老师这个参考答案是有一个文件夹判断bug的。
给你一个修正版答案 很好理解。
  1. import os
  2. def funcation(contents):
  3.     file_list = open(file_save,"a")
  4.     temp = {}
  5.     print("====================查询开始=======================")
  6.     print(">>>>>>>>>>>>>>>>>>>>>查询中>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
  7.     for each in os.walk(contents):
  8.         for each_name in each[2]:
  9.             if (os.path.splitext(each_name))[1].upper() in list_suf:
  10.                 file_list = open(file_save)
  11.                 r = file_list.read()
  12.                 file_list.close()
  13.                 if each_name not in r:
  14.                     file_list = open(file_save,"a")
  15.                     new_file = os.path.join(each[0],each_name)
  16.                     size = str(os.path.getsize(new_file))
  17.                     file_list.write(new_file+"\t"+"文件大小"+"->>"+size+"Bytes"+"\n\n")
  18.                     file_list.close()
  19.                 else:
  20.                     continue
  21.             else:
  22.                 continue
  23. try:
  24.     list_suf = [".TXT"]#需要检查的文件后缀
  25.     file_save = "D:\\1.txt"#统计结果存放路径
  26.     funcation("C:\")#主程序,需要检查的路径
  27. except FileNotFoundError as reason:
  28.     #有些隐藏文件是访问不了
  29.     print("该目录有无法限访问文件夹,文件如下:",reason)
  30. finally:
  31.     print("====================查询完毕=======================")
  32.     print("=================文件已经保存在:%s======"%(file_save))
复制代码

评分

参与人数 1荣誉 +3 鱼币 +5 贡献 +3 收起 理由
fujia1943 + 3 + 5 + 3 感谢楼主无私奉献!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2016-12-10 20:04:50 | 显示全部楼层
要查询什么文件 输入大写的 .AVI  这样的格式就可以
会把你所有的岛国动作片名字搞出来的
支持全盘搜索
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2016-12-12 08:33:33 | 显示全部楼层
hldh214 发表于 2016-12-9 17:05
看你的目录结构

能具体一点吗?这条递归调用之后返回上一层目录的逻辑和目的是什么?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2016-12-12 08:34:42 | 显示全部楼层
zua 发表于 2016-12-10 20:02
老师这个参考答案是有一个文件夹判断bug的。
给你一个修正版答案 很好理解。

虽然还是没有解答我的疑问,但是仍然感谢。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-11-29 22:24:36 | 显示全部楼层

我也是初学者,看完答案才写出代码,我当时是这么理解的:因为在开始目录下的文件夹中可能还是找不到目标文件,此时‘search_file(each_file, target) # 递归调用’这个语句结束,就要进入‘ os.chdir(os.pardir)返回上一层目录’这个语句,在开始目录下继续搜索。举个例子,假设你的开始目录为文件夹A,里面有且仅有一个文件夹B和目标文件1.txt,B内无任何文件或文件夹。此时程序从B文件夹查找,并且通过递归函数查询B文件夹内部。由于B文件夹内没有任何文件(自然也没有目标文件),所以没有任何输出结果,此时程序自然走到'os.chdir(os.pardir) # 递归调用后切记返回上一层目录',当前工作目录从B文件夹返回到上一级A文件夹,此时再进行查询,才能找到1.txt,程序结束
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-11-30 08:42:42 | 显示全部楼层
处理特殊情况,因为可能会有不止一个同一个文件名的文件,所以接着搜。你递归完了这个文件,要返回去,处理这个文件的上层目录中的其他文件。不回去,只能说就那一个文件,没有重复。
就像C:\PYTHON\A\B\我爱你.txt 和 C:\PYTHON\A\B\B1\C\C1\我爱你.txt 都存在
不返回上级就只有后面那个是吧
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-9-8 12:20:01 | 显示全部楼层
我的理解供参考:
给这三行代码编序号。假设start_dir为 e:\  e盘下有.\a\a1\a2\a.txt,.\b\b.txt,.\c\c1\c.txt....
<1>. if os.path.isdir(each_file) :
<2>.          search_file(each_file, target) # 递归调用
<3>.            os.chdir(os.pardir)
1行代码的判断是关键:isdir(each_file),用来判断,each_file是文件夹的时候才会进行<2>的递归调用。跳出递归调用的关键是,碰到each_file是文件的时候,就不会递归调用。这时候已经到了文件目录的最底层了,当然要跳出上一层目录。然后进行下一个文件夹的判断。以此类推。以上。
如果认为有些道理,可以私信我们深层次学习讨论。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-7-31 20:32:33 | 显示全部楼层
jle55555 发表于 2017-11-29 22:24
我也是初学者,看完答案才写出代码,我当时是这么理解的:因为在开始目录下的文件夹中可能还是找不到目标 ...

同初学者
看了你的回答后就恍然大悟了
谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-8-1 07:38:18 | 显示全部楼层
搜索算法的一种,回溯法,顾名思义要回退,回溯法(探索与回溯法)是一种选优搜索法,又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。

你在网上搜索一下回溯法的框架
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-8-1 23:40:08 | 显示全部楼层
1---
   1.1---
       1.2---
2---
    2.1--
介入有如上的文件树
假如没有进行返回上一层的操作,会往程序会从1文件夹走到1.1文件夹,在走到1.2夹。然后就没有然后了,程序走不到2文件夹里面。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-8-10 14:05:27 | 显示全部楼层
我自己写的代码和小甲鱼的答案不一样,但结果是一样的,我是这么写的:

def find_target(path, target):

    files_to_search = os.listdir(path)
    for each in files_to_search:
        if each == target:
            print("Got it!  " + path + os.sep + each)
        if os.path.isdir(path + os.sep + each):
            new_path = path + os.sep + each
            find_target(new_path, target)

我直接把os.listdir()的返回值赋值给空列表,然后遍历列表,如果列表中的某一项是文件夹,则递归调用。我水平也很粗糙,初学者,粗浅的分析认为,小甲鱼的代码里面的递归调用之所以要返回到上一层目录,是因为在函数定义最开始就使用了os.chdir(),所以,最后面的os.chdir(os.pardir)是和最开始的or.chdir()对应的。

我自己写的那段,因为直接就暴力采用了列表遍历,直接就可以遍历所有可能性,就用不着跳出了,当然了,我这个代码更丑,一点都不优雅就是了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-8-12 00:54:20 | 显示全部楼层
Stubborn 发表于 2019-8-1 23:40
1---
   1.1---
       1.2---

不是的吧?我把鱼C老师的答案最后一段删了,递归调用到最后一个文件夹里面没有找到的话,程序还是照样会执行递归前的FOR语句,但是没有进行后面的IF语句判断了,知道初次调用函数FOR语句执行完成,然后也不进行后面的IF判断,不知道为什么?


想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-8-12 01:01:51 | 显示全部楼层
SixPy 发表于 2016-12-9 17:32
def search_file(start_dir, target) :
    os.chdir(start_dir)

这个值在最后一次递归调用后会一直保持为最后一个文件夹的值吗?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-8-12 01:46:20 | 显示全部楼层
明白了,调用递归函数后,即使里面改变了当前工作目录,外面的函数也受影响,整个函数的工作目录都变了(和变量不一样,变量在调用递归后不会影响之前函数变量的值),然后for语句里面each_file应该是把最原来默认工作目录生成的文件列表都执行了一遍(虽然os.listdir(os.curdir)变了,但是不影响之前each_file的值),由于each_file的值只是相对路径不是绝对路径,工作目录变了就找不到相对路径下的文件了,所以后面的IF判断语句也就不成立了,因为找不到each_file这个文件。
实测出真知,我把 os.chdir(start_dir)删了后,为什么知道为什么结果出不来,特意在for后面加了一个print(each_flie),发现each_file值没有改变,和最开始for语句中的列表值一样,然后使用print(os.listdir(os.curdir))发现已经变成了最后一个递归函数执行完成后的工作目录,在最后一个程序最后面加了print(os.getcwd())发现每次递归返回的时候默认目录都变成了最后一个递归调用函数的工作目录。
希望对以后遇到困惑的小伙伴有所帮助,自学Python真的不容易。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-2-15 12:07:56 | 显示全部楼层
larryho 发表于 2019-8-10 14:05
我自己写的代码和小甲鱼的答案不一样,但结果是一样的,我是这么写的:

def find_target(path, target): ...

还是你这个好理解
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-6-27 17:22:53 | 显示全部楼层
jle55555 发表于 2017-11-29 22:24
我也是初学者,看完答案才写出代码,我当时是这么理解的:因为在开始目录下的文件夹中可能还是找不到目标 ...

讲的很清楚,赞
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-8-27 15:35:39 From FishC Mobile | 显示全部楼层
zata 发表于 2017-11-30 08:42
处理特殊情况,因为可能会有不止一个同一个文件名的文件,所以接着搜。你递归完了这个文件,要返回去,处理 ...

非常非常感谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-3-29 00:23

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表