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

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

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.


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

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

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

9

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

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

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.


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


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


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.


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

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

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

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

0

¿Al igual que?

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

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

-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
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.