working with method iter generators generadores python recursion iterator generator yield

with - python iter method



¿Cómo puedo atravesar un sistema de archivos con un generador? (6)

¿Por qué reinventar la rueda cuando puedes usar os.walk

import os for root, dirs, files in os.walk(path): for name in files: print os.path.join(root, name)

os.walk es un generador que proporciona los nombres de los archivos en un árbol de directorios al caminar por el árbol de arriba hacia abajo o de abajo hacia arriba

Estoy tratando de crear una clase de utilidad para atravesar todos los archivos en un directorio, incluidos aquellos dentro de los subdirectorios y subdirectorios. Intenté usar un generador porque los generadores son geniales; Sin embargo, me golpeó un obstáculo.

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)

Cuando el generador llega a un directorio, simplemente genera la ubicación de memoria del nuevo generador; No me da los contenidos del directorio.

¿Cómo puedo hacer que el generador ceda el contenido del directorio en lugar de un nuevo generador?

Si ya existe una función de biblioteca simple para enumerar de forma recursiva todos los archivos en una estructura de directorio, hágamelo saber. No pretendo replicar una función de biblioteca.


A partir de Python 3.4, puede usar el método glob() desde el módulo de pathlib incorporado:

import pathlib p = pathlib.Path(''.'') list(p.glob(''**/*'')) # lists all files recursively


A partir de Python 3.4, puede usar el módulo 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'')]

Esta es la respuesta esencial de la versión orientada a objetos de sjthebats . ¡Tenga en cuenta que el patrón Path.glob ** solo devuelve directorios!


Addendum a la respuesta de gerrit. Quería hacer algo más flexible.

listar todos los archivos en pth coincidan con un pattern dado, también puede listar los only_file si only_file es False

from pathlib import Path def walk(pth=Path(''.''), pattern=''*'', only_file=True) : """ list all files in pth matching a given pattern, can also list dirs if only_file is False """ if pth.match(pattern) and not (only_file and pth.is_dir()) : yield pth for sub in pth.iterdir(): if sub.is_dir(): yield from walk(sub, pattern, only_file) else: if sub.match(pattern) : yield sub


Estoy de acuerdo con la solución os.walk

Para fines puramente pedantes, intente iterar sobre el objeto generador, en lugar de devolverlo directamente:

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)


Puedes usar path.py Desafortunadamente, el sitio web del autor ya no está disponible, pero aún puede descargar el código desde PyPI. Esta biblioteca es una envoltura alrededor de las funciones de ruta en el módulo os .

path.py proporciona un método walkfiles() que devuelve un generador iterando recursivamente sobre todos los archivos en el directorio:

>>> from path import path >>> print path.walkfiles.__doc__ D.walkfiles() -> iterator over files in D, recursively. The optional argument, pattern, limits the results to files with names that match the pattern. For example, mydir.walkfiles(''*.tmp'') yields only files with the .tmp extension. >>> p = path(''/tmp'') >>> p.walkfiles() <generator object walkfiles at 0x8ca75a4> >>>