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.

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

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.


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

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

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

9

Cela semble fonctionner aussi (au moins sous Linux):

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

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.


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


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


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.


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

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

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

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

0

Ainsi?

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

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

-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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.