2011-07-10 19 views
20

Creo que la asignación de archivos y carpetas y hacer la parte + = [elemento] es un poco hackish. ¿Alguna sugerencia? Estoy usando Python 3,2¿Cuál es la forma de Python de recorrer un árbol de directorios?

from os import * 
from os.path import * 

def dir_contents(path): 
    contents = listdir(path) 
    files = [] 
    folders = [] 
    for i, item in enumerate(contents): 
     if isfile(contents[i]): 
      files += [item] 
     elif isdir(contents[i]): 
      folders += [item] 
    return files, folders 
+18

Evite 'from x import *'. * Eso es * un consejo para el estilo Pythonic. –

Respuesta

32

Echa un vistazo a la función os.walk, que devuelve la ruta junto con los directorios y archivos que contiene. Eso debería acortar considerablemente tu solución.

+0

Wow eso es perfecto, no puedo creer que lo haya echado de menos. Gracias. – Mike

+1

pero 'os.walk' no está limitado a un nivel de directorio como el código del OP. –

0

Pruebe usar el método append.

+0

+1: esto también es mucho mejor que 'list + = [item]'. * Las baterías * están incluidas * y la familiaridad con las características básicas del lenguaje le impide reinventar la batería: http://docs.python.org/tutorial/stdlib.html#batteries-included – msw

3
def dir_contents(path): 
    files,folders = [],[] 
    for p in listdir(path): 
     if isfile(p): files.append(p) 
     else: folders.append(p) 
    return files, folders 
4

hecho usando

items += [item] 

es malo por muchas razones ...

  1. El método append se ha hecho exactamente para que (introducción de un elemento al final de una lista)

  2. Usted están creando una lista temporal de un elemento solo para tirarlo. Si bien la velocidad bruta no debería ser su primera preocupación al usar Python (de lo contrario, está utilizando el lenguaje equivocado), perder velocidad sin razón no parece lo correcto.

  3. Está utilizando un poco de asimetría del lenguaje Python ... para los objetos de la lista de escritura a += b no es lo mismo que escribir a = a + b porque el primero modifica el objeto en su lugar, mientras que el segundo lugar asigna una nueva lista y esto puede tiene una semántica diferente si el objeto a también se puede alcanzar usando otras formas. En su código específico, este no parece ser el caso, pero podría convertirse en un problema más adelante cuando otra persona (o usted en unos años, que es lo mismo) tendrá que modificar el código. Python incluso tiene un método extend con una sintaxis menos sutil que está específicamente diseñada para manejar el caso en el que desea modificar en su lugar un objeto de lista al agregar al final los elementos de otra lista.

También como otros han señalado que parece que el código está tratando de hacer lo que ya lo hace os.walk ...

2

En lugar de la incorporada en el os.walk y os.path.walk, utilizo algo derivado de este trozo de código que encontré sugerido en otra parte:

http://code.google.com/p/mylibs/source/browse/lib/Python/MyPyLib/DirectoryStatWalker.py

no se pegar cualquier aquí, pero camina los directorios de forma recursiva y es muy eficiente y fácil de leer.

+0

+1 @mikebabcock gracias - esto funciona para mí out-of-the-box en Python 2.x (aunque el OP usa 3.x) necesitaba una solución 2.x. – therobyouknow

+0

Desafortunadamente ese proyecto ya no está disponible, 404. ¿Podría alguien repasarlo aquí? – LarsH

+1

No he comprobado si es idéntico aún, pero cf http://pymoex.googlecode.com/svn/trunk/os_path/directoryStatWalker.py @LarsH – mikebabcock

0

Mientras busqué la misma información en Google, encontré esta pregunta.

Estoy publicando aquí el código más pequeño y claro que encontré en http://www.pythoncentral.io/how-to-traverse-a-directory-tree-in-python-guide-to-os-walk/ (en lugar de simplemente publicar la URL, en caso de rotura del enlace).

La página tiene información útil y también apunta a algunas otras páginas relevantes.

# Import the os module, for the os.walk function 
import os 

# Set the directory you want to start from 
rootDir = '.' 
for dirName, subdirList, fileList in os.walk(rootDir): 
    print('Found directory: %s' % dirName) 
    for fname in fileList: 
     print('\t%s' % fname) 
0

no he probado esto extensivamente todavía, pero creo que este ampliará el generador os.walk, unirse a dirnames a todas las rutas de archivos, y aplanar la lista resultante; Para obtener una lista directa de archivos concretos en su ruta de búsqueda.

import itertools 
import os 

def find(input_path): 
    return itertools.chain(
     *list(
      list(os.path.join(dirname, fname) for fname in files) 
      for dirname, _, files in os.walk(input_path) 
     ) 
    ) 
1

Si desea recorrer de forma recursiva a través de todos los archivos, incluidos todos los archivos de las subcarpetas, creo que esta es la mejor manera.

import os 

def get_files(input): 
    for fd, subfds, fns in os.walk(input): 
     for fn in fns: 
      yield os.path.join(fd, fn) 

## now this will print all full paths 

for fn in get_files(fd): 
    print(fn) 
+1

Me gusta mucho este enfoque porque separa el código de iteración del sistema de archivos del código para procesar cada archivo! Sin embargo, se debe omitir la línea "yield from" - 'os.walk' ya entra en los subdirectorios, por lo que si también lo hace, verá los archivos del subdirectorio 2^n veces. –

+0

¡Tienes razón! Vaya ... – Gijs

1

Desde Python 3.4 hay un nuevo módulo pathlib. Entonces, para obtener todos los directorios y archivos uno puede hacer:

from pathlib import Path 

dirs = [str(item) for item in Path(path).iterdir() if item.is_dir()] 
files = [str(item) for item in Path(path).iterdir() if item.is_file()] 
Cuestiones relacionadas