【问题标题】:Optimized way to get to every file / folder in my dictionary访问字典中每个文件/文件夹的优化方式
【发布时间】:2015-07-20 21:30:52
【问题描述】:

我以为我已经弄清楚了 - “是的!最后,我成功地使用了递归函数 - 是的......哦哦不”

我有一本包含文件夹和文件的文件结构数据的字典:

{
    "FOLDER_NAME": {
        type: "dir",
        children: {
                    "FOLDER_NAME": {
                        type: "dir", 
                        children: { ... }
                    },
                    "FILE_NAME": {
                        type: "file",
                        url: '...'
                    },
                    "FILE_NAME": {
                        type: "file",
                        url: '...'
                    }
    }
}

我编写了以下递归函数来获取任何元素,只要它是一个目录,我想处理该目录的所有内容,只要目录中有一个目录,我想先处理该目录,所以上。 对process_dir 的初始调用使用dir_name="/root/path"dir_content 是上面的sn-p 和first = True

def process_dir(dir_name, dir_content, first):
    global download_path
    if first:
        download_path = dir_name + '/'
    else:
        download_path += clean_path(dir_name) + '/'
    full_path = download_path
    if not os.path.exists(full_path):
        os.makedirs(full_path)
    for x in dir_content:
        type = dir_content[x]['type']
        if type == 'dir':
            process_dir(x, dir_content[x]['children'], False)
        elif type == 'file':
            download_file(x, dir_content[x]['size'], dir_content[x]['url'])

这应该按预期工作吗?至少对我来说它没有按预期工作,因为它没有按顺序遍历字典中的每个节点。 在处理完某个目录的内容后,如何检测到它并返回到对该目录的process_dir 的原始调用,以便我可以从full_path 中删除最后一个子目录部分?


在 Javeed 的回答的帮助下,我能够解决我的问题,导致以下修改后的代码 sn-p:

def process_dir(path, new_name, dir_content):
    if not dir_content:
        return None
    new_path = path + '/' + new_name
    if not os.path.exists(new_path):
        os.makedirs(new_path)
    for x in dir_content:
        type = dir_content[x]['type']
        if type == 'dir':
            process_dir(new_path, clean_path(x), dir_content[x]['children'])
        elif type == 'file':
            download_file(new_path + '/' + clean_path(x), dir_content[x]['size'], dir_content[x]['url'])

【问题讨论】:

  • “应该按预期工作吗?”如果您告诉我们它是否适合您,会更容易。不过有一些通用提示:您应该能够避免使用global download_path,并使用os.path.join 连接路径名的各个部分。您可以通过调用process_dir(os.path.join(dir_name, x), ...) 来同时执行这两项操作(然后您也可以省略first 参数)。
  • @Evert first 参数与初始调用有关,因为我的clean_path 函数将去除除数,并且只能按单个目录或文件名调用。我可以摆脱全局download_path是的,谢谢。
  • os.path.join 不关心路径分隔符,因此无需手动删除并重新添加。例如os.path.join('/home', 'evert', 'Documents/', 'somefile.txt') 导致'/home/evert/Documents/somefile.txt':无需手动删除或附加'/'。事实上,如果你喜欢平台兼容,os.path.join 会考虑路径分隔符的差异(例如 Windows 上的 `\`)。

标签: python python-2.7 dictionary recursion


【解决方案1】:

这个有一些讨厌的禁忌:

global download_path

为了您自己的理智,请始终避免使用带有递归的全局变量。递归背后的想法是,东西是自下而上的,或者类似的东西。如果你正在阅读一个全局的,那么无论什么都可以,但是如果你修改递归调用堆栈之外的任何东西,它可能会一团糟。了解解决此问题的方法,例如传入值(看起来可以在这里工作)。

此外,您没有退出条件。当你到达没有子元素或条目的元素时会发生什么?虽然有时递归函数的结构可以在没有明确退出条件的情况下固有地允许它退出,但排除它被认为是非常糟糕的形式。类似的东西

if not dir_content: return None

或者诸如此类的东西会让它易于阅读。

至于这是否有效,取决于 download_file 和 clean_path 正在做什么,但我不会评论具体内容。相反,我会说,在回答您的最后一个问题时,您不需要检测它何时完成处理子目录的内容以更改全局路径,甚至不应该有全局路径。

尝试将您要添加的路径作为另一个参数传递。这确保了任何递归子调用将始终具有与父级相同的基本目录。无需修改。

这里有一些关于递归的其他技巧,因为你提到你是新手:

  1. 以抽象的方式规划您的递归。问三个大问题: 1. 在每一帧中我需要什么来完成预期的功能? 2. 我怎么知道我什么时候完成了? 3. 我想取回什么?

  2. 使用基本函数进行递归,我的意思是,一个启动函数,准备用于启动递归的信息。在您首先调用该参数的地方,只需创建一个调用一次的函数,该函数设置基本路径,然后将其作为输入开始递归。不应期望递归函数保持上下文感知。

【讨论】:

  • 我正在处理您的建议。同时我可以告诉你clean_path 只是将目录或文件名转换为经过清理的版本。 download_file 正在根据 url 值将文件下载到 /path/through/dirs/filename 位置,但不返回任何递归函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-11
  • 1970-01-01
相关资源
最近更新 更多