¿Cómo enumerar solo directorios de nivel superior en Python?

132

Quiero poder enumerar solo los directorios dentro de alguna carpeta. Esto significa que no quiero nombres de archivos en la lista, ni quiero subcarpetas adicionales.

Veamos si un ejemplo ayuda. En el directorio actual tenemos:

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

Sin embargo, no quiero que aparezcan nombres de archivos. Tampoco quiero subcarpetas como \ Lib \ curses. Esencialmente, lo que quiero funciona con lo siguiente:

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

Sin embargo, me pregunto si hay una manera más simple de lograr los mismos resultados. Tengo la impresión de que usar os.walk solo para devolver el nivel superior es ineficiente / demasiado.

fuentesjr
fuente

Respuestas:

125

Filtre el resultado usando os.path.isdir () (y use os.path.join () para obtener la ruta real):

>>> [ 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
fuente
17
Esto requiere mucho procesamiento frente a muy simple os.walk (). Next () [1]
Phyo Arkar Lwin
204

os.walk

Usar os.walkcon la nextfunción del artículo:

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

Para Python <= 2.5 use:

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

Como funciona esto

os.walkes un generador y la llamada nextobtendrá el primer resultado en forma de 3 tuplas (dirpath, dirnames, nombres de archivo). Por lo tanto, el [1]índice devuelve solo el dirnamesde esa tupla.

Alex Coventry
fuente
14
Una pequeña descripción más sobre esto es que este es un generador, no caminará por los otros directorios a menos que se lo indique. Entonces .next () [1] hace en una línea lo que hacen todas las comprensiones de listas. Probablemente haría algo así DIRNAMES=1y luego next()[DIRNAMES]para que sea más fácil de entender para futuros mantenedores de código.
Boatcoder
3
+1 solución asombrosa. Para especificar un directorio para navegar, use:os.walk( os.path.join(mypath,'.')).next()[1]
Daniel Reis
42
para python v3: next (os.walk ('.')) [1]
Andre Soares
si vas a hacer más que procesamiento de texto; es decir, el procesamiento en las carpetas reales, entonces podrían ser necesarias rutas completas:sorted( [os.path.join(os.getcwd(), item) for item in os.walk(os.curdir).next()[1]] )
DevPlayer
52

Filtre la lista usando os.path.isdir para detectar directorios.

filter(os.path.isdir, os.listdir(os.getcwd()))
Colin Jensen
fuente
55
Creo que esta es, con mucho, la mejor combinación de legibilidad y concisión en cualquiera de estas respuestas.
vergenzt
20
Esto no funcionó. Mi suposición es que os.listdirdevuelve un nombre de archivo / carpeta, pasado a os.path.isdir, pero este último necesita una ruta completa.
Daniel Reis
3
filtro es más rápido 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
fuente
44
Esto se puede acortar para filtrar (os.path.isdir, os.listdir (os.getcwd ())
John Millikin
3
¿Alguien tiene alguna información sobre si el filtro o la comprensión de una lista es más rápido? De lo contrario, es solo un argumento subjetivo. Por supuesto, esto supone que hay 10 millones de directorios en el cwd y el rendimiento es un problema.
Mark Roddy
12

Tenga en cuenta que, en lugar de hacerlo os.listdir(os.getcwd()), es preferible hacerlo os.listdir(os.path.curdir). Una llamada de función menos, y es tan portátil.

Entonces, para completar la respuesta, para obtener una lista de directorios en una carpeta:

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

Si prefiere nombres de ruta completos, use esta función:

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

Esto parece funcionar también (al menos en Linux):

import glob, os
glob.glob('*' + os.path.sep)
Travis
fuente
1
+1 para glob. Puede ahorrarle mucho código, especialmente iteraciones, y es muy similar al uso del terminal UNIX ( ls)
Gerard
55
En lugar de glob.glob ('*' + os.path.sep) es posible que desee escribir [dir para dir en glob.glob ("*") si os.path.isdir (dir)]
Eamonn MR
8

Solo para agregar que usar os.listdir () no " requiere mucho procesamiento frente a muy simple os.walk (). Next () [1]" . Esto se debe a que os.walk () usa os.listdir () internamente. De hecho, si los prueba juntos:

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

El filtrado de os.listdir () es muy ligeramente más rápido.

foz
fuente
2
Llegar a Python 3.5 es una forma más rápida de obtener el contenido del directorio: python.org/dev/peps/pep-0471
foz
1
pep-0471, el scandirpaquete, está felizmente disponible para Python 2.6 en adelante como un paquete instalable en PyPI. Ofrece reemplazos para os.walky os.listdirque son mucho más rápidos.
foz
6

Una forma mucho más simple y elegante es usar esto:

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

Ejecute este script en la misma carpeta para la que desea nombres de carpeta. Le dará exactamente el nombre inmediato de las carpetas (también sin la ruta completa de las carpetas).

manty
fuente
6

Usando la comprensión de la lista,

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

Creo que es la forma más sencilla

KBLee
fuente
2

siendo un novato aquí, aún no puedo comentar directamente, pero aquí hay una pequeña corrección que me gustaría agregar a la siguiente parte de la respuesta de ΤΖΩΤΖΙΟΥ :

Si prefiere nombres de ruta completos, use esta función:

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

Para aquellos que todavía están en Python <2.4 : la construcción interna debe ser una lista en lugar de una tupla y, por lo tanto, debería leer así:

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

de lo contrario, se obtiene un error de sintaxis.

antiplex
fuente
Sé que ha pasado un tiempo, pero este primer ejemplo realmente me ayudó.
Inbar Rose
1
Obtiene un error de sintaxis porque su versión no admite expresiones generadoras. Estos se introdujeron en Python 2.4, mientras que las comprensiones de listas han estado disponibles desde Python 2.0.
Awatts
1
[x for x in os.listdir(somedir) if os.path.isdir(os.path.join(somedir, x))]
Moe
fuente
1

Para obtener una lista de nombres de ruta completos, prefiero esta versión a las otras soluciones aquí:

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

Una opción más segura que no falla cuando no hay directorio.

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

¿Al igual que?

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

Python 3.4 introdujo el pathlibmódulo en la biblioteca estándar, que proporciona un enfoque orientado a objetos para manejar las rutas del sistema de archivos:

from pathlib import Path

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