2011-07-10 9 views
20

Ritengo che assegnare file e cartelle e fare la parte + = [item] sia un po 'hackerato. Eventuali suggerimenti? Sto usando Python 3,2Qual è il modo Python di camminare su un albero delle directory?

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

Evitare 'da x import *'. * Questo è * un consiglio per lo stile Pythonic. –

risposta

32

Date un'occhiata alla funzione os.walk che restituisce il percorso lungo con le directory ei file in essa contenuti. Ciò dovrebbe ridurre notevolmente la tua soluzione.

+0

Wow è perfetto, non posso credere di averlo perso. Grazie. – Mike

+1

ma 'os.walk' non è limitato a un livello di directory come il codice dell'OP. –

0

Provare a utilizzare il metodo append.

+0

+1: anche questo è molto meglio di 'list + = [item]'. Le batterie * sono escluse * e la familiarità con le funzionalità del linguaggio principale ti impedisce di reinventare la batteria: 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

Infatti utilizzando

items += [item] 

è male per molte ragioni ...

  1. Procedimento append è stata fatta esattamente per questo (aggiungendo un elemento al fine una lista)

  2. Tu stanno creando un elenco temporaneo di un elemento solo per buttarlo via. Mentre la velocità grezza non dovrebbe essere la tua prima preoccupazione quando usi Python (altrimenti stai utilizzando la lingua sbagliata) la velocità sprecata senza motivo non sembra la cosa giusta.

  3. Si sta utilizzando un po 'asimmetria del linguaggio Python ... per oggetti lista scrittura a += b non è lo stesso che scrivere a = a + b perché il primo modifica l'oggetto sul posto, mentre il secondo, invece alloca una nuova lista e questo può avere una semantica diversa se l'oggetto a è raggiungibile anche in altri modi. Nel tuo codice specifico questo non sembra il caso, ma potrebbe diventare un problema più tardi quando qualcun altro (o te stesso in pochi anni, è lo stesso) dovrà modificare il codice. Python ha anche un metodo extend con una sintassi meno sottile specificatamente creata per gestire il caso in cui si desidera modificare un oggetto elenco aggiungendo alla fine gli elementi di un altro elenco.

anche come altri hanno notato sembra che il codice sta cercando di fare quello che fa già os.walk ...

2

Invece del built-in os.walk e os.path.walk, io uso qualcosa derivato da questo pezzo di codice che ho trovato suggerito altrove:

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

non voglio repaste qui, ma cammina la directory in modo ricorsivo ed è abbastanza efficiente e di facile lettura.

+0

+1 @mikebabcock grazie - questo funziona per me out-of-the-box in Python 2.x (anche se l'OP utilizza 3.x) avevo bisogno di una soluzione 2.x. – therobyouknow

+0

Purtroppo quel progetto non è più disponibile, 404. Qualcuno potrebbe ripugnarlo qui? – LarsH

+1

Non ho ancora verificato se è identico, ma cf http://pymoex.googlecode.com/svn/trunk/os_path/directoryStatWalker.py @LarsH – mikebabcock

0

Mentre ho cercato su Google le stesse informazioni, ho trovato questa domanda.

Sto postando qui il codice più piccolo e più chiaro che ho trovato in http://www.pythoncentral.io/how-to-traverse-a-directory-tree-in-python-guide-to-os-walk/ (piuttosto che semplicemente postando l'URL, in caso di link rot).

La pagina contiene alcune informazioni utili e indica anche altre pagine pertinenti.

# 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

non ho ancora testato estensivamente questo, ma credo che questo amplierà il generatore os.walk, unire dirnames a tutti i percorsi dei file, e appiattire la lista risultante; Per dare un elenco diretto di file concreti nel percorso di ricerca.

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

Se volete iterare ricorsivamente tutti i file, compresi tutti i file nelle sottocartelle, credo che questo sia il modo migliore.

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

Mi piace molto questo approccio perché separa il codice di iterazione del file system dal codice per elaborare ogni file! Tuttavia, la riga "yield from" deve essere omessa - "os.walk" entra già nelle sottodirectory, quindi se lo fai anche tu, vedi i file sottodirectory 2^n volte. –

+0

Hai ragione! Oops .. – Gijs

1

Da Python 3.4 c'è un nuovo modulo pathlib. Quindi per ottenere tutti i file e le dir si può fare:

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()] 
Problemi correlati