【问题标题】:Recursive function to return a dictionary in Python在 Python 中返回字典的递归函数
【发布时间】:2022-01-08 21:09:13
【问题描述】:

我有上面的树。我需要以递归方式搜索树中的目录和文件,并将它们作为字典以以下形式返回-> 键:文件的目录/名称和值:文件的第一行

eg: key:1/2/5/test5    value:first line of test 5

到目前为止,我创建了下一个代码:

def search(root):
    items = os.listdir(root)
    
    for element in items:
        if os.path.isfile(element):
        
            with open (element) as file:
                one_line=file.readline()
                print(one_line)

        elif os.path.isdir(element):
            search(os.path.join(root,element))

问题是我的代码只搜索目录。请让我明白我错在哪里以及如何解决它。非常感谢任何帮助,谢谢!

【问题讨论】:

  • my code only searches the directories 是什么意思?为什么不在打印one_line之前使用字典保存文件信息?

标签: python file recursion directory


【解决方案1】:

您的代码几乎是正确的。不过,它必须稍微调整一下。 更具体地说,

  1. element 是文件或目录名称(不是路径)。如果它是子目录或子目录中的文件,则if os.path.isfile(element)elif os.path.isdir(element) 的值将始终为False。因此,将它们分别替换为if os.path.isfile(os.path.join(root, element))elif os.path.isdir(os.path.join(root, element))

  2. 同样,with open(element) 应替换为 with open(os.path.join(root,element))

  3. 读取文件的第一行时,您必须将路径和该行存储在字典中。

  4. 调用elif os.path.isdir(element)中的递归函数时必须更新该字典。

完整的sn-p见下文:

import os

def search(root):

    my_dict = {}   # this is the final dictionary to be populated

    for element in os.listdir(root):
        
        if os.path.isfile(os.path.join(root, element)):
            try: 
                with open(os.path.join(root, element)) as file:
                    my_dict[os.path.join(root, element)] = file.readline() # populate the dictionary
            except UnicodeDecodeError: 
                # This exception handling has been put here to ignore decode errors (some files cannot be read)
                pass

        elif os.path.isdir(os.path.join(root, element)):
            my_dict.update(search(os.path.join(root,element)))  # update the current dictionary with the one resulting from the recursive call

    return my_dict

print(search('.'))

它会打印如下的字典:

{
 "path/file.csv": "name,surname,grade",
 "path/to/file1.txt": "this is the first line of file 1",
 "path/to/file2.py": "import os"
}

为了可读性,os.path.join(root, element)可以存储在一个变量中,那么:

import os

def search(root):

    my_dict = {}   # this is the final dictionary to be populated

    for element in os.listdir(root):
        path = os.path.join(root, element)

        if os.path.isfile(path):
            with open(path) as file:
                my_dict[path] = file.readline()

        elif os.path.isdir(path):
            my_dict.update(search(path))

    return my_dict

print(search('.'))

【讨论】:

  • 你对我投了赞成票。问题是......正如你所说......对于os.path.isdiros.path.isfileos.path.join(root, element)。你能告诉我为什么需要为每个 isfile 和 isdir 进行连接吗?我想学习和写那是我的日志。请让我理解或将信息链接发​​送给我。
  • 在您的树中,您从仅存在“1”的目录开始搜索。因此,通过递归调用,元素将是“1”,然后是“2”,然后是“5”,然后是“test5”,依此类推。显然,它们不被识别为文件和目录,因为它们不在当前目录中。使用连接,元素将是“./1”,然后是“1/2”(第二次递归调用),然后是“1/2/5”(第三次递归调用),最后是“1/2/5/测试5”。即可以访问子目录和文件
  • 如果这能解决您的问题,请将答案标记为“已接受”
  • 完成,感谢您的帮助!
【解决方案2】:

您可以使用 os.walk

以下函数将不包含空文件夹。

def get_tree(startpath):
    tree = {}
    for root, dirs, files in os.walk(startpath):
        for file in files:
            path = root+"/"+file
            with open(path,'r') as f:
                first_line =  f.readline()
            tree[path] = first_line
    return tree

输出将是这样的:

{
    file_path : first_line_of_the_file,
    file_path2 : first_line_of_the_file2,
    ...
}

【讨论】:

  • 非常感谢您的帮助!:) 使用os.walk() 的想法是我的第二个选择。我真的很想创建一个递归函数来搜索目录,但是如果我找不到解决方案,我会尝试使用 os.walk()。
猜你喜欢
  • 2015-06-05
  • 2012-12-15
  • 1970-01-01
  • 2014-03-18
  • 2016-06-30
  • 1970-01-01
  • 2014-07-13
  • 2021-12-04
相关资源
最近更新 更多