Comment lister uniquement les répertoires de premier niveau en Python?

132

Je veux pouvoir lister uniquement les répertoires dans un dossier. Cela signifie que je ne veux pas que les noms de fichiers soient répertoriés, ni que je ne veux pas de sous-dossiers supplémentaires.

Voyons si un exemple aide. Dans le répertoire courant, nous avons:

>>> 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']

Cependant, je ne veux pas que les noms de fichiers soient répertoriés. Je ne veux pas non plus de sous-dossiers tels que \ Lib \ curses. Essentiellement, ce que je veux fonctionne avec les éléments suivants:

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

Cependant, je me demande s'il existe un moyen plus simple d'obtenir les mêmes résultats. J'ai l'impression qu'utiliser os.walk uniquement pour retourner le niveau supérieur est inefficace / trop.

fuentesjr
la source

Réponses:

125

Filtrez le résultat en utilisant os.path.isdir () (et utilisez os.path.join () pour obtenir le chemin réel):

>>> [ 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']
Thomas Wouters
la source
17
Cela prend beaucoup de traitement vs très simple os.walk (). Suivant () [1]
Phyo Arkar Lwin
204

os.walk

Utiliser os.walkavec nextla fonction d'élément:

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

Pour Python <= 2.5, utilisez:

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

Comment ça marche

os.walkest un générateur et l'appel nextobtiendra le premier résultat sous la forme d'un 3-tuple (dirpath, dirnames, filenames). Ainsi, l' [1]index ne renvoie que le dirnamesde ce tuple.

Alex Coventry
la source
14
Un peu plus de description à ce sujet est qu'il s'agit d'un générateur, il ne parcourra pas les autres répertoires à moins que vous ne le lui disiez. Donc .next () [1] fait en une ligne ce que font toutes les compréhensions de liste. Je ferais probablement quelque chose comme DIRNAMES=1et ensuite next()[DIRNAMES]pour le rendre plus facile à comprendre pour les futurs responsables du code.
boatcoder
3
+1 solution incroyable. Pour spécifier un répertoire à parcourir, utilisez:os.walk( os.path.join(mypath,'.')).next()[1]
Daniel Reis
42
pour python v3: next (os.walk ('.')) [1]
Andre Soares
si vous allez faire plus que le traitement de texte; c'est-à-dire que le traitement dans les dossiers réels, puis les chemins complets peuvent être nécessaires:sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
DevPlayer
52

Filtrez la liste à l'aide de os.path.isdir pour détecter les répertoires.

filter(os.path.isdir, os.listdir(os.getcwd()))
Colin Jensen
la source
5
Je pense que c'est de loin la meilleure combinaison de lisibilité et de concision dans l'une de ces réponses.
vergenzt
20
Cela n'a pas fonctionné. Je suppose que cela os.listdirrenvoie un nom de fichier / dossier, transmis à os.path.isdir, mais ce dernier a besoin d'un chemin complet.
Daniel Reis
3
le filtre est plus rapide que 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)]
Mark Roddy
la source
4
Cela peut être raccourci pour filtrer (os.path.isdir, os.listdir (os.getcwd ())
John Millikin
3
Quelqu'un a-t-il des informations pour savoir si la compréhension d'un filtre ou d'une liste est plus rapide? Sinon, c'est juste un argument subjectif. Cela suppose bien sûr qu'il y a 10 millions de répertoires dans le cwd et que les performances sont un problème.
Mark Roddy
12

Notez qu'au lieu de faire os.listdir(os.getcwd()), il est préférable de le faire os.listdir(os.path.curdir). Un appel de fonction en moins, et c'est aussi portable.

Donc, pour compléter la réponse, pour obtenir une liste de répertoires dans un dossier:

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

Si vous préférez les chemins d'accès complets, utilisez cette fonction:

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

Cela semble fonctionner aussi (au moins sous Linux):

import glob, os
glob.glob('*' + os.path.sep)
Travis
la source
1
+1 pour glob. Cela peut vous faire économiser beaucoup de code, en particulier les itérations, et ressemble beaucoup à l'utilisation du terminal UNIX ( ls)
Gerard
5
Plutôt que glob.glob ('*' + os.path.sep), vous pouvez écrire [dir for dir dans glob.glob ("*") if os.path.isdir (dir)]
Eamonn MR
8

Juste pour ajouter qu'utiliser os.listdir () ne "prend pas beaucoup de traitement par rapport à os.walk (). Next () [1]" très simple . C'est parce que os.walk () utilise os.listdir () en interne. En fait si vous les testez ensemble:

>>>> 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

Le filtrage de os.listdir () est très légèrement plus rapide.

foz
la source
2
Venir en Python 3.5 est un moyen plus rapide d'obtenir le contenu du répertoire: python.org/dev/peps/pep-0471
foz
1
pep-0471 - le scandirpaquet - est heureusement disponible pour Python 2.6 en tant que paquet installable sur PyPI. Il propose des remplacements pour os.walket os.listdirqui sont beaucoup plus rapides.
foz
6

Une manière beaucoup plus simple et élégante est d'utiliser ceci:

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

Exécutez ce script dans le même dossier pour lequel vous voulez des noms de dossier.Il vous donnera exactement le nom des dossiers immédiats uniquement (cela aussi sans le chemin complet des dossiers).

mante
la source
6

Utilisation de la compréhension de liste,

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

Je pense que c'est le moyen le plus simple

KBLee
la source
2

étant un débutant ici, je ne peux pas encore commenter directement mais voici une petite correction que j'aimerais ajouter à la partie suivante de la réponse de ΤΖΩΤΖΙΟΥ :

Si vous préférez les chemins d'accès complets, utilisez cette fonction:

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

pour ceux qui utilisent encore python <2.4 : la construction interne doit être une liste au lieu d'un tuple et doit donc se lire comme ceci:

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

sinon on obtient une erreur de syntaxe.

antiplex
la source
Je sais que ça fait un moment, mais ce premier exemple m'a vraiment aidé.
Inbar Rose
1
Vous obtenez une erreur de syntaxe car votre version ne prend pas en charge les expressions de générateur. Ceux-ci ont été introduits dans Python 2.4 alors que les compréhensions de liste sont disponibles depuis Python 2.0.
awatts
1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]
Moe
la source
1

Pour une liste des noms de chemins complets, je préfère cette version aux autres solutions ici:

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))]
Malius Arth
la source
1
scanDir = "abc"
directories = [d for d in os.listdir(scanDir) if os.path.isdir(os.path.join(os.path.abspath(scanDir), d))]
nvd
la source
0

Une option plus sûre qui n'échoue pas lorsqu'il n'y a pas de répertoire.

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 []
Alexey Gavrilov
la source
0

Ainsi?

>>>> [path for path in os.listdir(os.getcwd()) if os.path.isdir(path)]
Kirk Strauser
la source
0

Python 3.4 a introduit le pathlibmodule dans la bibliothèque standard, qui fournit une approche orientée objet pour gérer les chemins du système de fichiers:

from pathlib import Path

p = Path('./')
[f for f in p.iterdir() if f.is_dir()]
joelostblom
la source
-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
venkata maddineni
la source