laocaiye 发表于 4 天前

关于第55讲永久存储(下)动动手第1题

为方便说明,先把小鱼老师的源代码贴出:
from pathlib import Path
   
def get_files(p, files):
    for each in p.iterdir():
      if str(each) == __file__:
            continue
      if each.is_file() and each.suffix == '.py':
            files.append(each)
      if each.is_dir():
            p = each
            get_files(p, files) # 此处使用递归搜索会更方便
   
    return files
   
   
def count_lines(files):
    lines = 0
    for each in files:
      with open(each, "r", errors="ignore") as f:
            t = f.readlines()
            lines += len(t) - t.count('\n') # 空行不能算,所以要减去空行数量
   
    return lines
   
   
p = Path.cwd()
files = []
   
files = get_files(p, files)
for each in files:
    print(each)
#print(f"一个有 {count_lines(files)} 行代码~")


红色部分是我们的关注点。下面两行红色代码是我测试加的代码,下面有两个问题:
1、经测试,函数get_files(p, files)返回的files列表中仍然包含本程序文件,这是怎么回事?
2、使用files.remove(__file__)为何不能从files中删除本程序?

FishC 发表于 4 天前

关于您在第55讲动动手第1题中遇到的问题,我来逐一解释并提供解决方案。

首先,问题核心在于路径比较和类型匹配。以下是详细分析:

问题1:为什么 get_files 函数返回的列表中包含本程序文件?
原因在于代码中使用 str(each) == __file__ 进行比较时,路径的字符串表示可能不一致(例如,绝对路径 vs 相对路径,或大小写差异)。__file__ 返回的是字符串,而 each 是 Path 对象,直接转换为字符串后可能不匹配。

解决方案:改用 Path 对象进行精确比较。修改 get_files 函数中的检查条件。

问题2:为什么 files.remove(__file__) 无法删除本程序文件?
这是因为 files 列表中的元素是 Path 对象,而 __file__ 是字符串。在 Python 中,不同类型对象即使路径相同,也不会被视为相等,因此 remove() 方法找不到匹配项。

解决方案:在删除时使用 Path 对象,或先将列表元素转换为字符串。

以下是修改后的代码示例,解决上述问题:


from pathlib import Path

def get_files(p, files):
    current_file = Path(__file__)# 将当前文件路径转为 Path 对象
    for each in p.iterdir():
      if each == current_file:# 直接比较 Path 对象
            continue
      if each.is_file() and each.suffix == '.py':
            files.append(each)
      if each.is_dir():
            get_files(each, files)# 递归时传递当前目录
    return files

def count_lines(files):
    lines = 0
    for each in files:
      with open(each, "r", errors="ignore") as f:
            t = f.readlines()
            lines += len(t) - t.count('\n')
    return lines

p = Path.cwd()
files = []# 初始化空列表
files = get_files(p, files)

# 如果需要额外删除本程序文件(通常不需要,因为函数已跳过)
# 可以使用:files.remove(Path(__file__))

for each in files:
    print(each)
# print(f"一个有 {count_lines(files)} 行代码~")


关键修改点:
- 在 get_files 中,使用 Path(__file__) 创建当前文件的 Path 对象,并通过 each == current_file 进行比较。
- 递归调用时,直接传递 each(目录路径),避免修改原 p。
- 初始化 files 为空列表。

这样修改后,列表将正确跳过本程序文件,且删除操作(如需要)应使用 Path 对象。如果还有疑问,请随时提出!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: 关于第55讲永久存储(下)动动手第1题