避免递归树遍历中的基本路径

Avoid the base path in a recursive tree walking

我知道如何使用各种方法递归列出 d:\temp 的所有 files/folders,请参阅 How to use glob() to find files recursively?
但通常我想避免在结果中使用 d:\temp\ 前缀,而是使用到此基础的相对路径。

这可以通过以下方式完成:

这 3 种解决方案有效。但实际上,如果您阅读 glob.py 的源代码,它会执行 accumulate/join all 路径部分。所以上面的解决方案是......“删除之前刚刚添加的东西”!它有效,但不是很优雅。 pathlibrelative_to 相同,删除了前缀。

问题:如何修改接下来的几行,使输出中没有 d:\temp(不删除之前连接的内容!)?

import os

def listpath(path):
    for f in os.scandir(path):
        f2 = os.path.join(path, f)
        if os.path.isdir(f):
            yield f2
            yield from listpath(f2)
        else:
            yield f2

for f in listpath('d:\temp'):
    print(f)

#d:\temp\New folder
#d:\temp\New folder\New Text Document - Copy.txt
#d:\temp\New folder\New Text Document.txt
#d:\temp\New Text Document - Copy.txt
#d:\temp\New Text Document.txt

您可以执行以下示例中所示的操作。基本上,我们递归地 return 将路径部分连接在一起,但我们不连接初始根。

import os

def listpath(root, parent=''):
    scan = os.path.join(root, parent)
    for f in os.scandir(scan):
        f2 = os.path.join(parent, f.name)
        yield f2
        if f.is_dir():
            yield from listpath(root, f2)

for f in listpath('d:\temp'):
    print(f)

在尚未发布的 Python 3.10 中,将有一个新的 root_dir 选项,可以让您毫无问题地使用内置 glob 执行此操作:

import glob
glob.glob('**/*', root_dir='d:\temp', recursive=True)

您还可以使用第 3 方库,例如 wcmatch 库,它已经实现了此行为(我是其作者)。但在这种简单的情况下,您的 listpath 方法可能就足够了。