首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >编写一个递归函数来列出parts.txt的所有路径

编写一个递归函数来列出parts.txt的所有路径
EN

Stack Overflow用户
提问于 2019-11-25 04:07:22
回答 1查看 44关注 0票数 2

编写一个函数list_files_recursive,该函数返回所有parts.txt文件的路径列表,而不使用os模块的遍历生成器。相反,该函数应该使用递归。输入将是一个目录名。这是我到目前为止的代码,我认为它基本上是正确的,但发生的情况是输出不是一个完整的列表?

代码语言:javascript
复制
def list_files_recursive(top_dir):
    rec_list_files = []
    list_dir = os.listdir(top_dir)
    for item in list_dir:
        item_path = os.path.join(top_dir, item)
        if os.path.isdir(item_path):
            list_files_recursive(item_path)
        else:
            if os.path.basename(item_path) == 'parts.txt': 
                rec_list_files.append(os.path.join(item_path))
    print(rec_list_files)
    return rec_list_files

这是我得到的输出的一部分(来自print语句):

代码语言:javascript
复制
['CarItems/Honda/Accord/1996/parts.txt']
[]
['CarItems/Honda/Odyssey/2000/parts.txt']
['CarItems/Honda/Odyssey/2002/parts.txt']
[]

所以问题是,它不是一个列表,而且里面有空列表。我不太明白为什么这不起作用,我已经尝试了所有的方法来解决它。在这方面任何帮助都是非常感谢的!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-11-28 09:31:59

这非常接近,但问题是list_files_recursive的子调用不会将结果传回父调用。一种方法是将每个子调用的所有列表连接在一起,或者在整个调用链中传递对单个列表的引用。

请注意,在rec_list_files.append(os.path.join(item_path))中,只有一个参数的os.path.join是没有意义的。作为side effect,应该省略print(rec_list_files),这会使输出难以解释--只有在调用方中打印。另外,

代码语言:javascript
复制
else:
    if ... :

在这里可以更清晰地写成elif:,因为它们在逻辑上是等价的。只要有可能,减少条件句的嵌套总是一个好主意。

下面是通过扩展父列表来工作的方法:

代码语言:javascript
复制
import os 

def list_files_recursive(top_dir):
    files = []

    for item in os.listdir(top_dir):
        item_path = os.path.join(top_dir, item)

        if os.path.isdir(item_path):
            files.extend(list_files_recursive(item_path)) 
            #     ^^^^^^ add child results to parent
        elif os.path.basename(item_path) == "parts.txt": 
            files.append(item_path)

    return files

if __name__ == "__main__":
    print(list_files_recursive("foo"))

或者通过调用树传递结果列表:

代码语言:javascript
复制
import os 

def list_files_recursive(top_dir, files=[]):
    for item in os.listdir(top_dir):
        item_path = os.path.join(top_dir, item)

        if os.path.isdir(item_path):
            list_files_recursive(item_path, files)
            #                               ^^^^^ pass our result list recursively
        elif os.path.basename(item_path) == "parts.txt": 
            files.append(item_path)

    return files

if __name__ == "__main__":
    print(list_files_recursive("foo"))

这些函数的一个主要问题是,由于字符串字面值为hard coded,因此它们只适用于查找精确命名为parts.txt的文件。这使得它几乎对任何事情都没有用,除了直接的目的。我们应该添加一个参数,允许调用者指定他们想要搜索的目标文件,从而使函数具有通用性。

另一个问题是,该函数并没有像它的名字所宣称的那样:list_files_recursive实际上应该被称为find_file_recursive,或者,由于使用了硬编码字符串,所以应该被称为find_parts_txt_recursive

除此之外,该函数是转换为generator函数的有力候选者,这是遍历的常见Python语言,特别是当子目录可能包含大量数据的情况下,这些数据一次保存在内存中的成本很高。生成器还允许在第一次匹配后使用该函数取消搜索的灵活性,从而进一步增强其(重新)可用性。

yield关键字还使函数代码本身非常整洁--我们可以避免完全保留结果数据结构的问题,只需按需触发结果项。

我是这样写的:

代码语言:javascript
复制
import os 

def find_file_recursive(top_dir, target):
    for item in os.listdir(top_dir):
        item_path = os.path.join(top_dir, item)

        if os.path.isdir(item_path):
            yield from find_file_recursive(item_path, target)
        elif os.path.basename(item_path) == target:
            yield item_path

if __name__ == "__main__":
    print(list(find_file_recursive("foo", "parts.txt")))
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59021874

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档