在任意深度的嵌套字典上行走/迭代(字典代表目录树)

dri*_*her 7 python iteration tree recursion dictionary

我几乎可以肯定有一个简单的解决方案,但我现在花了几个小时阅读和重读相同的一组相关结果,这些结果并没有完全解决我的问题.

这个问题的背景(包括完成但可以跳过这个)

出现这种情况是因为我希望用户能够从目录(以及任何子目录)中选择一组文件,不幸的是,Tkinter在文件对话框中选择多个文件的默认功能在Windows 7上被破坏(http:/ /bugs.python.org/issue8010).

因此,我试图通过另一种方法(仍然使用Tkinter)来表示目录结构:构建目录结构的传真,由标记和缩进复选框(在树中组织)组成.因此像这样的目录:

\SomeRootDirectory
    \foo.txt
    \bar.txt
    \Stories
        \Horror
            \scary.txt
            \Trash
                \notscary.txt
        \Cyberpunk
    \Poems
        \doyoureadme.txt
Run Code Online (Sandbox Code Playgroud)

看起来像这样(其中#代表一个checkbutton):

SomeRootDirectory
    # foo.txt
    # bar.txt
    Stories
        Horror
            # scary.txt
            Trash
                # notscary.txt
        Cyberpunk
    Poems
        # doyoureadme.txt
Run Code Online (Sandbox Code Playgroud)

使用我在ActiveState中找到的某个配方(见下文),可以很容易地从目录结构构建原始字典,但是当我尝试迭代我留下的精美嵌套字典时,我遇到了问题.而且我认为我需要迭代它以便使用树的漂亮网格表示来填充Tkinter帧.然后我希望通过解释哪些复选框为true或false来加载用户选择的各种文本文件.除了在修复深度的情况下迭代字典外,一切看起来都相当容易.

用更抽象的术语来说

要制作这些嵌套的词典,我使用的是ActiveState配方 - http://code.activestate.com/recipes/577879/.它实现了os.walk来制作如下的字典:

a={
    'SomeRootDirectory': {
        'foo.txt': None,
        'bar.txt': None,
        'Stories': {
            'Horror': {
                'horror.txt' : None,
                'Trash' : {
                    'notscary.txt' : None,
                    },
                },
            'Cyberpunk' : None
            },
        'Poems' : {
            'doyoureadme.txt' : None
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在此之后我感到难过.在撰写本文时,我是一名Python新手

解决方案改编自spicavigo的反应

#distinguish between directory and file
dirtab = "/==="
filetab = "|---"

Parents={-1:"Root"}
def add_dir(level, parent, index, k):
    print (dirtab*level)+k
def add_file(level, parent, index, k):
    #Currently an empty folder gets passed to add_file; here's a quick treatment.
    if "." in k:
        print (filetab*level)+k
    else:
        print (dirtab*level)+k
def addemup(level=0, parent=-1, index=0, di={}):
    for k in di:
        index +=1
        if di[k]:
            Parents[index]=k
            add_dir(level, parent, index, k)
            addemup(level+1, index, index, di[k])
        else:
            add_file(level, parent, index, k)

addemup(di=a) #dictionary from above
Run Code Online (Sandbox Code Playgroud)

这会产生一些我认为很容易修改为Tkinter表示的东西:

SomeRootDirectory
/===Poems
|---|---doyoureadme.txt
/===Stories
/===/===Horror
|---|---|---rickscott.txt
/===/===/===Trash
|---|---|---|---notscary.txt
/===/===Cyberpunk
|---foo.txt
|---bar.txt
Run Code Online (Sandbox Code Playgroud)

谢谢,这个社区令人难以置信.

oad*_*ams 9

这是一个打印所有文件名的函数.它遍历字典中的所有键,如果它们映射到非字典的东西(在您的情况下,文件名),我们打印出名称.否则,我们在映射到的字典上调用该函数.

def print_all_files(directory):

    for filename in directory.keys():
        if not isinstance(directory[filename], dict):
            print filename
        else:
            print_all_files(directory[filename])
Run Code Online (Sandbox Code Playgroud)

因此,可以修改此代码以执行任何操作,但这只是一个示例,说明如何通过使用递归来避免修复深度.

要理解的关键是每次调用print_all_files时,它都不知道它在树中的深度.它只是查看那里的文件,并打印名称.如果有直升机,它就会在它们上运行.


spi*_*igo 4

这是初步代码。仔细检查并告诉我你在哪里遇到问题。

Parents={-1:"Root"}
def add_dir(level, parent, index, k):
    print "Directory"
    print "Level=%d, Parent=%s, Index=%d, value=%s" % (level, Parents[parent], index, k)
def add_file(parent, index, k):
    print "File"
    print "Parent=%s, Index=%d, value=%s" %  (Parents[parent], index, k)
def f(level=0, parent=-1, index=0, di={}):
    for k in di:
        index +=1
        if di[k]:
            Parents[index]=k
            add_dir(level, parent, index, k)
            f(level+1, index, index, di[k])
        else:
            add_file(parent, index, k)

a={
    'SomeRootDirectory': {
        'foo.txt': None,
        'bar.txt': None,
        'Stories': {
            'Horror': {
                'scary.txt' : None,
                'Trash' : {
                    'notscary.txt' : None,
                    },
                },
            'Cyberpunk' : None
            },
        'Poems' : {
            'doyoureadme.txt' : None
        }
    }
}

f(di=a)
Run Code Online (Sandbox Code Playgroud)