Hice algunas pruebas de velocidad en varias funciones para devolver la ruta completa a todos los subdirectorios actuales.
tl; dr:
siempre use scandir:
list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bonificación: con scandirusted también solo puede obtener nombres de carpetas utilizando en f.namelugar de f.path.
Esto (así como todas las demás funciones a continuación) no utilizará la ordenación natural . Esto significa que los resultados se ordenarán así: 1, 10, 2. Para obtener una clasificación natural (1, 2, 10), consulte https://stackoverflow.com/a/48030307/2441026
Resultados :
scandires: 3x más rápido que walk, 32x más rápido que listdir(con filtro), 35x más rápido que Pathliby 36x más rápido que listdiry 37x (!) Más rápido que glob.
Probado con W7x64, Python 3.8.1. Carpeta con 440 subcarpetas.
En caso de que se pregunte si listdirpodría acelerarse al no hacer os.path.join () dos veces, sí, pero la diferencia es básicamente inexistente.
Código:
import os
import pathlib
import timeit
import glob
path = r"<example_path>"def a():
list_subfolders_with_paths =[f.path for f in os.scandir(path)if f.is_dir()]# print(len(list_subfolders_with_paths))def b():
list_subfolders_with_paths =[os.path.join(path, f)for f in os.listdir(path)if os.path.isdir(os.path.join(path, f))]# print(len(list_subfolders_with_paths))def c():
list_subfolders_with_paths =[]for root, dirs, files in os.walk(path):for dir in dirs:
list_subfolders_with_paths.append( os.path.join(root, dir))break# print(len(list_subfolders_with_paths))def d():
list_subfolders_with_paths = glob.glob(path +'/*/')# print(len(list_subfolders_with_paths))def e():
list_subfolders_with_paths = list(filter(os.path.isdir,[os.path.join(path, f)for f in os.listdir(path)]))# print(len(list(list_subfolders_with_paths)))def f():
p = pathlib.Path(path)
list_subfolders_with_paths =[x for x in p.iterdir()if x.is_dir()]# print(len(list_subfolders_with_paths))print(f"Scandir: {timeit.timeit(a, number=1000):.3f}")print(f"Listdir: {timeit.timeit(b, number=1000):.3f}")print(f"Walk: {timeit.timeit(c, number=1000):.3f}")print(f"Glob: {timeit.timeit(d, number=1000):.3f}")print(f"Listdir (filter): {timeit.timeit(e, number=1000):.3f}")print(f"Pathlib: {timeit.timeit(f, number=1000):.3f}")
¿Por qué nadie ha mencionado glob? globle permite usar la expansión de nombre de ruta de estilo Unix, y es mi función para casi todo lo que necesita encontrar más de un nombre de ruta. Lo hace muy fácil:
from glob import glob
paths = glob('*/')
Tenga en cuenta que globdevolverá el directorio con la barra diagonal final (como lo haría Unix), mientras que la mayoría de las pathsoluciones basadas omitirán la barra diagonal final.
Buena solución, simple y funciona. Para aquellos que no quieren ese corte final, puede usar esto paths = [ p.replace('/', '') for p in glob('*/') ].
Evan Hu
55
Puede ser más seguro simplemente cortar el último carácter [p[:-1] for p in paths], ya que ese método de reemplazo también reemplazará las barras diagonales escapadas en el nombre del archivo (no es que sean comunes).
Ari
3
Aún más seguro, use la tira ('/') para eliminar las barras diagonales. De esta manera se garantiza que no se eliminarán los caracteres que no sean barras diagonales
Eliezer Miron,
8
Por construcción, se garantiza que tendrá una barra inclinada (por lo que no es más seguro), pero creo que es más legible. Sin embargo, definitivamente desea usar en rstriplugar de strip, ya que este último convertirá las rutas totalmente calificadas en rutas relativas.
ari
77
complemento al comentario de @ari para los novatos de Python como I: strip('/')eliminará tanto el inicio como el final '/', rstrip('/')eliminará solo el final
Extremadamente inteligente. Si bien la eficiencia no importa ( ... lo hace totalmente ), tengo curiosidad por saber si esto o la expresión del generador basada en glob (s.rstrip("/") for s in glob(parent_dir+"*/"))es más eficiente en el tiempo. Mi sospecha intuitiva es que una solución stat()basada debería ser profundamente más rápida que el glob de estilo shell. Lamentablemente, me falta la voluntad y realmente lo descubro. os.walk()timeit
Cecil Curry
3
Tenga en cuenta que esto devuelve los nombres de subdirectorio sin el nombre del directorio principal prefijado.
Paul Chernoch
19
import os, os.path
Para obtener subdirectorios inmediatos (ruta completa) en un directorio:
defSubDirPath(d):return filter(os.path.isdir,[os.path.join(d,f)for f in os.listdir(d)])
walk () genera los nombres de archivo en un árbol de directorios, caminando el árbol de arriba hacia abajo o de abajo hacia arriba. Para cada directorio en el árbol enraizado en la parte superior del directorio (incluida la parte superior), produce una tupla de 3 (dirpath, dirnames, nombres de archivo).
Solo tenga en cuenta que si solo desea los subdirectorios de primer nivel, salga de la iteración os.walk después del primer conjunto de valores de retorno.
Yoyo
11
Este método lo hace todo de una vez.
from glob import glob
subd =[s.rstrip("/")for s in glob(parent_dir+"*/")]
from twisted.python.filepath importFilePathdef subdirs(pathObj):for subpath in pathObj.walk():if subpath.isdir():yield subpath
if __name__ =='__main__':for subdir in subdirs(FilePath(".")):print"Subdirectory:", subdir
Dado que algunos comentaristas han preguntado cuáles son las ventajas de usar las bibliotecas de Twisted para esto, iré un poco más allá de la pregunta original aquí.
Hay una documentación mejorada en una rama que explica las ventajas de FilePath; tal vez quieras leer eso.
Más específicamente en este ejemplo: a diferencia de la versión de biblioteca estándar, esta función se puede implementar sin importar . La función "subdire" es totalmente genérica, en el sentido de que opera únicamente con su argumento. Para copiar y mover los archivos utilizando la biblioteca estándar, debe depender de " open" incorporado listdir",", quizás " isdir" o " os.walk" o " shutil.copy". Quizás " os.path.join" también. Sin mencionar el hecho de que necesita una cadena pasó un argumento para identificar el archivo real. Echemos un vistazo a la implementación completa que copiará el "index.tpl" de cada directorio a "index.html":
def copyTemplates(topdir):for subdir in subdirs(topdir):
tpl = subdir.child("index.tpl")if tpl.exists():
tpl.copyTo(subdir.child("index.html"))
La función "subdire" anterior puede funcionar en cualquier FilePathobjeto similar. Lo que significa, entre otras cosas, ZipPathobjetos. Lamentablemente, ZipPathes de solo lectura en este momento, pero podría ampliarse para admitir la escritura.
También puede pasar sus propios objetos con fines de prueba. Para probar las API que usan os.path sugeridas aquí, debe usar los nombres importados y las dependencias implícitas y, en general, realizar magia negra para que sus pruebas funcionen. Con FilePath, haces algo como esto:
classMyFakePath:def child(self, name):"Return an appropriate child object"def walk(self):"Return an iterable of MyFakePath objects"def exists(self):"Return true or false, as appropriate to the test"def isdir(self):"Return true or false, as appropriate to the test"...
subdirs(MyFakePath(...))
Como tengo poca exposición a Twisted, siempre agradezco información y ejemplos adicionales; esta respuesta es agradable de ver para eso. Habiendo dicho eso, dado que este enfoque parece requerir mucho más trabajo que el uso de los módulos integrados de Python y una instalación Twisted, ¿hay alguna ventaja en usar esto que pueda agregar a la respuesta?
Jarret Hardie
1
La respuesta de Glyph probablemente se inspiró en el hecho de que TwistedLore también usa archivos .tpl.
Constantin
Bueno, claramente no espero la inquisición española :-) Asumí que "* .tpl" era una referencia genérica a alguna extensión abstracta que significa "plantilla", y no una plantilla Twisted específica (he visto que .tpl se usa en muchos idiomas después de todo). Bueno saber.
Jarret Hardie
+1, por lo tanto, para girar al posible ángulo Twisted, aunque todavía me gustaría entender lo que el objeto Twisted'd 'FilePath' y la función 'walk ()' agregan a la API estándar.
Jarret Hardie
Personalmente, encuentro que "FilePath.walk () produce objetos de ruta" mucho más fácil de recordar que "os.walk produce 3-tuplas de dir, dirs, archivos". Pero hay otros beneficios. FilePath permite el polimorfismo, lo que significa que puede atravesar otras cosas que no sean sistemas de archivos. Por ejemplo, podría pasar un twisted.python.zippath.ZipArchive a mi función 'subdireccionar' y obtener un generador de ZipPaths en lugar de FilePaths; su lógica no cambia, pero su aplicación ahora maneja mágicamente archivos zip. Si desea probarlo, solo tiene que proporcionar un objeto, no tiene que escribir archivos reales.
Glifo
4
Acabo de escribir un código para mover máquinas virtuales vmware, y terminé usando os.pathy shutilpara realizar la copia de archivos entre subdirectorios.
-1: no funcionará, ya que shutil.copy se copiará en el directorio actual, por lo que terminará sobrescribiendo 'index.html' en el directorio actual una vez por cada 'index.tpl' que encuentre en el árbol del subdirectorio.
nosklo
1
Tengo que mencionar la biblioteca path.py , que uso con mucha frecuencia.
Obtener los subdirectorios inmediatos se vuelve tan simple como eso:
my_dir.dirs()
El ejemplo de trabajo completo es:
from path importPath
my_directory =Path("path/to/my/directory")
subdirs = my_directory.dirs()
NB: my_directory todavía se puede manipular como una cadena, ya que Path es una subclase de cadena, pero proporciona un montón de métodos útiles para manipular rutas
funciona bien, la versión Python 3.6, pero necesitaba borrar "self", desde las variables de función internas
locometro
1
estaba usando dentro de una clase, he actualizado
Kanish Mathew
0
import glob
import os
def child_dirs(path):
cd = os.getcwd()# save the current working directory
os.chdir(path)# change directory
dirs = glob.glob("*/")# get all the subdirectories
os.chdir(cd)# change directory to the script original locationreturn dirs
La child_dirsfunción toma una ruta en un directorio y devuelve una lista de los subdirectorios inmediatos en él.
dir
|-- dir_1
-- dir_2
child_dirs('dir')->['dir_1','dir_2']
Respuestas:
Hice algunas pruebas de velocidad en varias funciones para devolver la ruta completa a todos los subdirectorios actuales.
tl; dr: siempre use
scandir
:list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bonificación: con
scandir
usted también solo puede obtener nombres de carpetas utilizando enf.name
lugar def.path
.Esto (así como todas las demás funciones a continuación) no utilizará la ordenación natural . Esto significa que los resultados se ordenarán así: 1, 10, 2. Para obtener una clasificación natural (1, 2, 10), consulte https://stackoverflow.com/a/48030307/2441026
Resultados :
scandir
es: 3x más rápido quewalk
, 32x más rápido quelistdir
(con filtro), 35x más rápido quePathlib
y 36x más rápido quelistdir
y 37x (!) Más rápido queglob
.Probado con W7x64, Python 3.8.1. Carpeta con 440 subcarpetas.
En caso de que se pregunte si
listdir
podría acelerarse al no hacer os.path.join () dos veces, sí, pero la diferencia es básicamente inexistente.Código:
fuente
fuente
¿Por qué nadie ha mencionado
glob
?glob
le permite usar la expansión de nombre de ruta de estilo Unix, y es mi función para casi todo lo que necesita encontrar más de un nombre de ruta. Lo hace muy fácil:Tenga en cuenta que
glob
devolverá el directorio con la barra diagonal final (como lo haría Unix), mientras que la mayoría de laspath
soluciones basadas omitirán la barra diagonal final.fuente
paths = [ p.replace('/', '') for p in glob('*/') ]
.[p[:-1] for p in paths]
, ya que ese método de reemplazo también reemplazará las barras diagonales escapadas en el nombre del archivo (no es que sean comunes).rstrip
lugar destrip
, ya que este último convertirá las rutas totalmente calificadas en rutas relativas.strip('/')
eliminará tanto el inicio como el final '/',rstrip('/')
eliminará solo el finalMarque " Obtener una lista de todos los subdirectorios en el directorio actual ".
Aquí hay una versión de Python 3:
fuente
(s.rstrip("/") for s in glob(parent_dir+"*/"))
es más eficiente en el tiempo. Mi sospecha intuitiva es que una soluciónstat()
basada debería ser profundamente más rápida que el glob de estilo shell. Lamentablemente, me falta la voluntad y realmente lo descubro.os.walk()
timeit
Para obtener subdirectorios inmediatos (ruta completa) en un directorio:
Para obtener el último (más nuevo) subdirectorio:
fuente
list( filter(...) )
.os.walk
Es tu amigo en esta situación.Directamente de la documentación:
fuente
Este método lo hace todo de una vez.
fuente
Usando el módulo FilePath de Twisted:
Dado que algunos comentaristas han preguntado cuáles son las ventajas de usar las bibliotecas de Twisted para esto, iré un poco más allá de la pregunta original aquí.
Hay una documentación mejorada en una rama que explica las ventajas de FilePath; tal vez quieras leer eso.
Más específicamente en este ejemplo: a diferencia de la versión de biblioteca estándar, esta función se puede implementar sin importar . La función "subdire" es totalmente genérica, en el sentido de que opera únicamente con su argumento. Para copiar y mover los archivos utilizando la biblioteca estándar, debe depender de "
open
" incorporadolistdir
",", quizás "isdir
" o "os.walk
" o "shutil.copy
". Quizás "os.path.join
" también. Sin mencionar el hecho de que necesita una cadena pasó un argumento para identificar el archivo real. Echemos un vistazo a la implementación completa que copiará el "index.tpl" de cada directorio a "index.html":La función "subdire" anterior puede funcionar en cualquier
FilePath
objeto similar. Lo que significa, entre otras cosas,ZipPath
objetos. Lamentablemente,ZipPath
es de solo lectura en este momento, pero podría ampliarse para admitir la escritura.También puede pasar sus propios objetos con fines de prueba. Para probar las API que usan os.path sugeridas aquí, debe usar los nombres importados y las dependencias implícitas y, en general, realizar magia negra para que sus pruebas funcionen. Con FilePath, haces algo como esto:
fuente
Acabo de escribir un código para mover máquinas virtuales vmware, y terminé usando
os.path
yshutil
para realizar la copia de archivos entre subdirectorios.No es terriblemente elegante, pero funciona.
fuente
Aquí hay una manera:
fuente
Tengo que mencionar la biblioteca path.py , que uso con mucha frecuencia.
Obtener los subdirectorios inmediatos se vuelve tan simple como eso:
my_dir.dirs()
El ejemplo de trabajo completo es:
fuente
La siguiente función se puede llamar como:
get_folders_in_directories_recursively (directorio, índice = 1) -> da la lista de carpetas en el primer nivel
get_folders_in_directories_recursively (directorio) -> da todas las subcarpetas
fuente
La
child_dirs
función toma una ruta en un directorio y devuelve una lista de los subdirectorios inmediatos en él.fuente
fuente
Un revestimiento usando pathlib:
fuente