Come elencare solo le directory di livello superiore in Python?


132

Voglio essere in grado di elencare solo le directory all'interno di alcune cartelle. Questo significa che non voglio elencare i nomi dei file, né voglio sottocartelle aggiuntive.

Vediamo se un esempio aiuta. Nella directory corrente abbiamo:

>>> os.listdir(os.getcwd())
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'LICENSE.txt', 'mod_p
ython-wininst.log', 'NEWS.txt', 'pymssql-wininst.log', 'python.exe', 'pythonw.ex
e', 'README.txt', 'Removemod_python.exe', 'Removepymssql.exe', 'Scripts', 'tcl',
 'Tools', 'w9xpopen.exe']

Tuttavia, non voglio elencare i nomi dei file. Né voglio sottocartelle come \ Lib \ curses. Essenzialmente quello che voglio funziona con quanto segue:

>>> for root, dirnames, filenames in os.walk('.'):
...     print dirnames
...     break
...
['cx_Oracle-doc', 'DLLs', 'Doc', 'include', 'Lib', 'libs', 'Scripts', 'tcl', 'Tools']

Tuttavia, mi chiedo se esiste un modo più semplice per ottenere gli stessi risultati. Ho l'impressione che l'utilizzo di os.walk solo per restituire il livello superiore sia inefficiente / troppo.

Risposte:


125

Filtra il risultato usando os.path.isdir () (e usa os.path.join () per ottenere il percorso reale):

>>> [ name for name in os.listdir(thedir) if os.path.isdir(os.path.join(thedir, name)) ]
['ctypes', 'distutils', 'encodings', 'lib-tk', 'config', 'idlelib', 'xml', 'bsddb', 'hotshot', 'logging', 'doc', 'test', 'compiler', 'curses', 'site-packages', 'email', 'sqlite3', 'lib-dynload', 'wsgiref', 'plat-linux2', 'plat-mac']

17
Questo richiede molta elaborazione e os.walk () molto semplice. Next () [1]
Phyo Arkar Lwin

204

os.walk

Utilizzare os.walkcon la nextfunzione oggetto:

next(os.walk('.'))[1]

Per Python <= 2.5 usare:

os.walk('.').next()[1]

Come funziona

os.walkè un generatore e la chiamata nextotterrà il primo risultato sotto forma di una 3 tupla (dirpath, dirnames, nomi di file). Quindi l' [1]indice restituisce solo il dirnamesda quella tupla.


14
Una piccola descrizione in più su questo è che questo è un generatore, non camminerà tra le altre directory a meno che tu non lo dica. Quindi .next () [1] fa in una riga ciò che fanno tutte le comprensioni dell'elenco. Probabilmente farei qualcosa del genere DIRNAMES=1e quindi next()[DIRNAMES]per rendere più facile la comprensione per i futuri manutentori del codice.
barcacoder

3
+1 soluzione straordinaria. Per specificare una directory da esplorare, utilizzare:os.walk( os.path.join(mypath,'.')).next()[1]
Daniel Reis il

42
per python v3: next (os.walk ('.')) [1]
Andre Soares,

se hai intenzione di fare di più, allora l'elaborazione del testo; cioè elaborando nelle cartelle effettive potrebbero essere necessari percorsi completi:sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
DevPlayer

52

Filtra l'elenco utilizzando os.path.isdir per rilevare le directory.

filter(os.path.isdir, os.listdir(os.getcwd()))

5
Penso che questa sia di gran lunga la migliore combinazione di leggibilità e concisione in una di queste risposte.
vergenzt,

20
Questo non ha funzionato. La mia ipotesi è che os.listdirrestituisca un nome di file / cartella, passato a os.path.isdir, ma quest'ultimo ha bisogno di un percorso completo.
Daniel Reis,

3
il filtro è più veloce di os.walk timeit(os.walk(os.getcwd()).next()[1]) 1000 loops, best of 3: 734 µs per loop timeit(filter(os.path.isdir, os.listdir(os.getcwd()))) 1000 loops, best of 3: 477 µs per loop
B.Kocis,

14
directories=[d for d in os.listdir(os.getcwd()) if os.path.isdir(d)]

4
Questo può essere abbreviato per filtrare (os.path.isdir, os.listdir (os.getcwd ())
John Millikin,

3
Qualcuno ha qualche informazione sul fatto se il filtro o la comprensione di un elenco sia più veloce? Altrimenti è solo un argomento soggettivo. Questo ovviamente presuppone che ci siano 10 milioni di directory nel CWD e che le prestazioni siano un problema.
Mark Roddy,

12

Nota che, invece di farlo os.listdir(os.getcwd()), è preferibile farlo os.listdir(os.path.curdir). Una chiamata di funzione in meno ed è portatile.

Quindi, per completare la risposta, per ottenere un elenco di directory in una cartella:

def listdirs(folder):
    return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]

Se preferisci i percorsi completi, usa questa funzione:

def listdirs(folder):
    return [
        d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
        if os.path.isdir(d)
    ]

9

Anche questo sembra funzionare (almeno su Linux):

import glob, os
glob.glob('*' + os.path.sep)

1
+1 per glob. Può farti risparmiare un sacco di codice, in particolare iterazioni, ed è molto simile all'utilizzo del terminale UNIX ( ls)
Gerard

5
Invece di glob.glob ('*' + os.path.sep) potresti voler scrivere [dir per dir in glob.glob ("*") se os.path.isdir (dir)]
Eamonn MR

8

Solo per aggiungere che usare os.listdir () non "richiede molta elaborazione e os.walk (). Next () [1]" molto semplice . Questo perché os.walk () utilizza os.listdir () internamente. Infatti se li testate insieme:

>>>> import timeit
>>>> timeit.timeit("os.walk('.').next()[1]", "import os", number=10000)
1.1215229034423828
>>>> timeit.timeit("[ name for name in os.listdir('.') if os.path.isdir(os.path.join('.', name)) ]", "import os", number=10000)
1.0592019557952881

Il filtraggio di os.listdir () è leggermente più veloce.


2
Venire in Python 3.5 è un modo più veloce per ottenere i contenuti delle directory: python.org/dev/peps/pep-0471
foz

1
pep-0471 - il scandirpacchetto - è felicemente disponibile per Python da 2.6 in poi come pacchetto installabile su PyPI. Offre sostituzioni per os.walke os.listdirche sono molto più veloci.
Foz

6

Un modo molto più semplice ed elegante è usare questo:

 import os
 dir_list = os.walk('.').next()[1]
 print dir_list

Esegui questo script nella stessa cartella per cui desideri i nomi delle cartelle. Ti darà esattamente solo il nome delle cartelle immediate (anche quello senza il percorso completo delle cartelle).


6

Utilizzando la comprensione dell'elenco,

[a for a in os.listdir() if os.path.isdir(a)]

Penso che sia il modo più semplice


2

essendo un principiante qui non posso ancora commentare direttamente ma ecco una piccola correzione che vorrei aggiungere alla parte seguente della risposta di ΤΖΩΤΖΙΟΥ :

Se preferisci i percorsi completi, usa questa funzione:

def listdirs(folder):  
  return [
    d for d in (os.path.join(folder, d1) for d1 in os.listdir(folder))
    if os.path.isdir(d)
]

per quelli ancora su Python <2.4 : il costrutto interno deve essere un elenco anziché una tupla e quindi dovrebbe essere letto come questo:

def listdirs(folder):  
  return [
    d for d in [os.path.join(folder, d1) for d1 in os.listdir(folder)]
    if os.path.isdir(d)
  ]

altrimenti si ottiene un errore di sintassi.


so che è passato un po 'di tempo, ma questo primo esempio mi ha davvero aiutato.
Inbar Rose,

1
Viene visualizzato un errore di sintassi perché la versione non supporta le espressioni del generatore. Questi sono stati introdotti in Python 2.4 mentre la comprensione dell'elenco è disponibile da Python 2.0.
risveglia il

1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]

1

Per un elenco di nomi di percorso completi preferisco questa versione alle altre soluzioni qui:

def listdirs(dir):
    return [os.path.join(os.path.join(dir, x)) for x in os.listdir(dir) 
        if os.path.isdir(os.path.join(dir, x))]

1
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]

0

Un'opzione più sicura che non fallisce quando non c'è directory.

def listdirs(folder):
    if os.path.exists(folder):
         return [d for d in os.listdir(folder) if os.path.isdir(os.path.join(folder, d))]
    else:
         return []

0

Così?

>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]

0

Python 3.4 ha introdotto il pathlibmodulo nella libreria standard, che fornisce un approccio orientato agli oggetti per gestire i percorsi del filesystem:

from pathlib import Path

p = Path('./')
[f for f in p.iterdir() if f.is_dir()]

-1
-- This will exclude files and traverse through 1 level of sub folders in the root

def list_files(dir):
    List = []
    filterstr = ' '
    for root, dirs, files in os.walk(dir, topdown = True):
        #r.append(root)
        if (root == dir):
            pass
        elif filterstr in root:
            #filterstr = ' '
            pass
        else:
            filterstr = root
            #print(root)
            for name in files:
                print(root)
                print(dirs)
                List.append(os.path.join(root,name))
            #print(os.path.join(root,name),"\n")
                print(List,"\n")

    return List
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.