如何使用生成器遍历文件系统?

Eva*_*ske 24 python recursion iterator yield generator

我正在尝试创建一个实用程序类来遍历目录中的所有文件,包括子目录和子子目录中的文件.我试图使用发电机,因为发电机很酷; 但是,我遇到了麻烦.


def grab_files(directory):
    for name in os.listdir(directory):
        full_path = os.path.join(directory, name)
        if os.path.isdir(full_path):
            yield grab_files(full_path)
        elif os.path.isfile(full_path):
            yield full_path
        else:
            print('Unidentified name %s. It could be a symbolic link' % full_path)
Run Code Online (Sandbox Code Playgroud)

当生成器到达目录时,它只是产生新生成器的内存位置; 它没有给我目录的内容.

如何让生成器生成目录的内容而不是新的生成器?

如果已经有一个简单的库函数来递归列出目录结构中的所有文件,请告诉我它.我不打算复制库函数.

Nad*_*mli 57

为什么在使用os.walk时重新发明轮子

import os
for root, dirs, files in os.walk(path):
    for name in files:
        print os.path.join(root, name)
Run Code Online (Sandbox Code Playgroud)

os.walk是一个生成器,它通过从上到下或从下到上遍历树来生成目录树中的文件名

  • 但话说再说一遍,通过重新发明轮子,我们可以"os.cycle"而不是"os.walk"...... (47认同)
  • 我认为这是一个笑话......"重新发明轮子"?散步与骑自行车?非常好.. :) (9认同)
  • os.walk可能是一个生成器,但它的粒度是一个目录级别,它返回的文件是一个列表.如果你有一个包含数百万个文件的目录,那么使用os.walk祝你好运.至少在2.7中也是如此. (9认同)

the*_*bat 12

我同意os.walk解决方案

出于纯粹的迂腐目的,尝试迭代生成器对象,而不是直接返回它:


def grab_files(directory):
    for name in os.listdir(directory):
        full_path = os.path.join(directory, name)
        if os.path.isdir(full_path):
            for entry in grab_files(full_path):
                yield entry
        elif os.path.isfile(full_path):
            yield full_path
        else:
            print('Unidentified name %s. It could be a symbolic link' % full_path)
Run Code Online (Sandbox Code Playgroud)


Ein*_*oll 9

从Python 3.4开始,您可以使用glob()内置pathlib模块中的方法:

import pathlib
p = pathlib.Path('.')
list(p.glob('**/*'))    # lists all files recursively
Run Code Online (Sandbox Code Playgroud)

  • 只是为了确认,`type(p.glob('** / *'))`确实会返回`generator`。 (2认同)

ger*_*rit 8

从Python 3.4开始,您可以使用Pathlib模块:

In [48]: def alliter(p):
   ....:     yield p
   ....:     for sub in p.iterdir():
   ....:         if sub.is_dir():
   ....:             yield from alliter(sub)
   ....:         else:
   ....:             yield sub
   ....:             

In [49]: g = alliter(pathlib.Path("."))                                                                                                                                                              

In [50]: [next(g) for _ in range(10)]
Out[50]: 
[PosixPath('.'),
 PosixPath('.pypirc'),
 PosixPath('.python_history'),
 PosixPath('lshw'),
 PosixPath('.gstreamer-0.10'),
 PosixPath('.gstreamer-0.10/registry.x86_64.bin'),
 PosixPath('.gconf'),
 PosixPath('.gconf/apps'),
 PosixPath('.gconf/apps/gnome-terminal'),
 PosixPath('.gconf/apps/gnome-terminal/%gconf.xml')]
Run Code Online (Sandbox Code Playgroud)

这对sjthebats的面向对象版本至关重要.请注意,Path.glob **模式仅返回目录!