J'ai fait des tests de vitesse sur diverses fonctions pour renvoyer le chemin complet vers tous les sous-répertoires actuels.
tl; dr:
utilisez toujours scandir:
list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bonus: Avec scandirvous pouvez également obtenir simplement les noms de dossiers en utilisant f.nameau lieu de f.path.
Ceci (ainsi que toutes les autres fonctions ci-dessous) n'utilisera pas le tri naturel . Cela signifie que les résultats seront triés comme suit: 1, 10, 2. Pour obtenir un tri naturel (1, 2, 10), veuillez consulter https://stackoverflow.com/a/48030307/2441026
Résultats :
scandirest: 3x plus rapide que walk, 32x plus rapide que listdir(avec filtre), 35x plus rapide que Pathlibet 36x plus rapide que listdiret 37x (!) Plus rapide que glob.
Testé avec W7x64, Python 3.8.1. Dossier avec 440 sous-dossiers.
Au cas où vous vous demanderiez si cela listdirpourrait être accéléré en ne faisant pas os.path.join () deux fois, oui, mais la différence est pratiquement inexistante.
Code:
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}")
Pourquoi personne n'a mentionné glob? globvous permet d'utiliser l'expansion des noms de chemin de style Unix, et c'est ma fonction préférée pour presque tout ce qui a besoin de trouver plus d'un nom de chemin. Cela rend les choses très faciles:
from glob import glob
paths = glob('*/')
Notez que globcela renverra le répertoire avec la barre oblique finale (comme le ferait unix) tandis que la plupart des pathsolutions basées omettra la barre oblique finale.
Bonne solution, simple et fonctionne. Pour ceux qui ne veulent pas de cette dernière barre oblique, il peut l'utiliser paths = [ p.replace('/', '') for p in glob('*/') ].
Evan Hu
5
Il peut être plus sûr de simplement couper le dernier caractère avec [p[:-1] for p in paths], car cette méthode replace remplacera également toutes les barres obliques échappées dans le nom de fichier (non pas que celles-ci soient courantes).
ari
3
Encore plus sûr, utilisez strip ('/') pour supprimer les barres obliques de fin. De cette façon, vous ne coupez aucun caractère autre que des barres obliques
Eliezer Miron
8
Par construction, vous êtes assuré d'avoir une barre oblique à la fin (donc ce n'est pas plus sûr), mais je pense que c'est plus lisible. Cependant, vous voulez certainement utiliser à la rstripplace de strip, car ce dernier transformera tous les chemins complets en chemins relatifs.
ari
7
complément au commentaire @ari pour les débutants en python tels que I: strip('/')supprimera à la fois le début et la fin '/', rstrip('/')ne supprimera que le dernier
Extrêmement intelligent. Bien que l'efficacité ne compte pas ( ... c'est totalement le cas ), je suis curieux de savoir si cette expression ou celle du générateur basé sur glob (s.rstrip("/") for s in glob(parent_dir+"*/"))est plus efficace en temps. Mon soupçon intuitif est qu'une solution stat()basée sur une base devrait être profondément plus rapide que le globbing de type shell. Malheureusement, je n'ai pas la volonté de le découvrir. os.walk()timeit
Cecil Curry
3
Notez que cela renvoie les noms de sous-répertoire sans le nom du répertoire parent préfixé.
Paul Chernoch
19
import os, os.path
Pour obtenir (chemin complet) des sous-répertoires immédiats dans un répertoire:
defSubDirPath(d):return filter(os.path.isdir,[os.path.join(d,f)for f in os.listdir(d)])
Pour obtenir le dernier sous-répertoire (le plus récent):
walk () génère les noms de fichiers dans une arborescence de répertoires, en parcourant l'arborescence de haut en bas ou de bas en haut. Pour chaque répertoire de l'arborescence enraciné au sommet du répertoire (y compris le sommet lui-même), il donne un 3-tuple (dirpath, dirnames, fichiers).
Sachez simplement que si vous ne voulez que les sous-répertoires de premier niveau, sortez de l'itération os.walk après le premier ensemble de valeurs de retour.
yoyo
11
Cette méthode fait tout cela en une seule fois.
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
Étant donné que certains commentateurs ont demandé quels sont les avantages d'utiliser les bibliothèques de Twisted pour cela, je vais aller un peu au-delà de la question originale ici.
Il existe une documentation améliorée dans une branche qui explique les avantages de FilePath; vous voudrez peut-être lire cela.
Plus précisément dans cet exemple: contrairement à la version standard de la bibliothèque, cette fonction peut être implémentée sans importation . La fonction "sous-répertoires" est totalement générique, en ce qu'elle n'opère que sur son argument. Pour copier et déplacer les fichiers en utilisant la bibliothèque standard, vous devez dépendre du " open" builtin listdir"," peut-être " isdir" ou " os.walk" ou " shutil.copy". Peut-être " os.path.join" aussi. Sans parler du fait que vous avez besoin d'une chaîne passée un argument pour identifier le fichier réel. Jetons un coup d'œil à l'implémentation complète qui copiera "index.tpl" de chaque répertoire dans "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 fonction "sous-répertoires" ci-dessus peut fonctionner sur n'importe quel FilePathobjet semblable. Ce qui signifie, entre autres, des ZipPathobjets. MalheureusementZipPath est actuellement en lecture seule, mais il pourrait être étendu pour prendre en charge l'écriture.
Vous pouvez également transmettre vos propres objets à des fins de test. Afin de tester les API utilisant os.path suggérées ici, vous devez singe avec des noms importés et des dépendances implicites et généralement effectuer de la magie noire pour que vos tests fonctionnent. Avec FilePath, vous faites quelque chose comme ceci:
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(...))
Comme je suis peu exposé à Twisted, je suis toujours heureux d'avoir des informations et des exemples supplémentaires; cette réponse est agréable à voir pour cela. Cela dit, étant donné que cette approche semble nécessiter beaucoup plus de travail que l'utilisation des modules python intégrés et une installation Twisted, y a-t-il des avantages à utiliser cela que vous pourriez ajouter à la réponse?
Jarret Hardie
1
La réponse de Glyph a probablement été inspirée par le fait que TwistedLore utilise également des fichiers .tpl.
Constantin
Eh bien, clairement, je ne m'attends pas à l'inquisition espagnole :-) J'ai supposé que "* .tpl" était une référence générique à une extension abstraite signifiant "modèle", et non à un modèle Twisted spécifique (j'ai vu .tpl utilisé dans beaucoup langues après tout). Bon à savoir.
Jarret Hardie
+1 donc pour ramener à l'angle Twisted possible, bien que j'aimerais quand même comprendre ce que l'objet 'FilePath' et la fonction 'walk ()' de Twisted ajoutent à l'API standard.
Jarret Hardie
Personnellement, je trouve que "FilePath.walk () produit des objets de chemin" est beaucoup plus facile à retenir que "os.walk donne 3-tuples de dir, dirs, files". Mais il y a d'autres avantages. FilePath permet le polymorphisme, ce qui signifie que vous pouvez parcourir des choses autres que des systèmes de fichiers. Par exemple, vous pouvez passer un twisted.python.zippath.ZipArchive à ma fonction 'sous-répertoires' et obtenir un générateur de ZipPaths au lieu de FilePaths; votre logique ne change pas, mais votre application gère désormais comme par magie les fichiers zip. Si vous voulez le tester, il vous suffit de fournir un objet, vous n'avez pas à écrire de vrais fichiers.
Glyph
4
Je viens d'écrire du code pour déplacer les machines virtuelles vmware, et j'ai fini par utiliser os.pathet shutilpour effectuer la copie de fichiers entre les sous-répertoires.
-1: ne fonctionnera pas, car shutil.copy copiera dans le répertoire actuel, vous finirez donc par écraser «index.html» dans le répertoire actuel une fois pour chaque «index.tpl» que vous trouverez dans l'arborescence des sous-répertoires.
nosklo
1
Je dois mentionner la bibliothèque path.py , que j'utilise très souvent.
Récupérer les sous-répertoires immédiats devient aussi simple que cela:
my_dir.dirs()
L'exemple de travail complet est:
from path importPath
my_directory =Path("path/to/my/directory")
subdirs = my_directory.dirs()
NB: my_directory peut toujours être manipulé comme une chaîne, puisque Path est une sous-classe de string, mais fournit un tas de méthodes utiles pour manipuler les chemins
faire bien, version python 3.6, mais j'avais besoin d'effacer "self", à partir des variables de fonction internes
locometro
1
utilisait à l'intérieur d'une classe, ont mis à jour
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_dirsfonction prend un chemin dans un répertoire et retourne une liste des sous-répertoires immédiats qu'il contient .
dir
|-- dir_1
-- dir_2
child_dirs('dir')->['dir_1','dir_2']
Réponses:
J'ai fait des tests de vitesse sur diverses fonctions pour renvoyer le chemin complet vers tous les sous-répertoires actuels.
tl; dr: utilisez toujours
scandir
:list_subfolders_with_paths = [f.path for f in os.scandir(path) if f.is_dir()]
Bonus: Avec
scandir
vous pouvez également obtenir simplement les noms de dossiers en utilisantf.name
au lieu def.path
.Ceci (ainsi que toutes les autres fonctions ci-dessous) n'utilisera pas le tri naturel . Cela signifie que les résultats seront triés comme suit: 1, 10, 2. Pour obtenir un tri naturel (1, 2, 10), veuillez consulter https://stackoverflow.com/a/48030307/2441026
Résultats :
scandir
est: 3x plus rapide quewalk
, 32x plus rapide quelistdir
(avec filtre), 35x plus rapide quePathlib
et 36x plus rapide quelistdir
et 37x (!) Plus rapide queglob
.Testé avec W7x64, Python 3.8.1. Dossier avec 440 sous-dossiers.
Au cas où vous vous demanderiez si cela
listdir
pourrait être accéléré en ne faisant pas os.path.join () deux fois, oui, mais la différence est pratiquement inexistante.Code:
la source
la source
Pourquoi personne n'a mentionné
glob
?glob
vous permet d'utiliser l'expansion des noms de chemin de style Unix, et c'est ma fonction préférée pour presque tout ce qui a besoin de trouver plus d'un nom de chemin. Cela rend les choses très faciles:Notez que
glob
cela renverra le répertoire avec la barre oblique finale (comme le ferait unix) tandis que la plupart despath
solutions basées omettra la barre oblique finale.la source
paths = [ p.replace('/', '') for p in glob('*/') ]
.[p[:-1] for p in paths]
, car cette méthode replace remplacera également toutes les barres obliques échappées dans le nom de fichier (non pas que celles-ci soient courantes).rstrip
place destrip
, car ce dernier transformera tous les chemins complets en chemins relatifs.strip('/')
supprimera à la fois le début et la fin '/',rstrip('/')
ne supprimera que le dernierCochez " Obtenir une liste de tous les sous-répertoires dans le répertoire courant ".
Voici une version de Python 3:
la source
(s.rstrip("/") for s in glob(parent_dir+"*/"))
est plus efficace en temps. Mon soupçon intuitif est qu'une solutionstat()
basée sur une base devrait être profondément plus rapide que le globbing de type shell. Malheureusement, je n'ai pas la volonté de le découvrir.os.walk()
timeit
Pour obtenir (chemin complet) des sous-répertoires immédiats dans un répertoire:
Pour obtenir le dernier sous-répertoire (le plus récent):
la source
list( filter(...) )
.os.walk
est votre ami dans cette situation.Directement à partir de la documentation:
la source
Cette méthode fait tout cela en une seule fois.
la source
Utilisation du module FilePath de Twisted:
Étant donné que certains commentateurs ont demandé quels sont les avantages d'utiliser les bibliothèques de Twisted pour cela, je vais aller un peu au-delà de la question originale ici.
Il existe une documentation améliorée dans une branche qui explique les avantages de FilePath; vous voudrez peut-être lire cela.
Plus précisément dans cet exemple: contrairement à la version standard de la bibliothèque, cette fonction peut être implémentée sans importation . La fonction "sous-répertoires" est totalement générique, en ce qu'elle n'opère que sur son argument. Pour copier et déplacer les fichiers en utilisant la bibliothèque standard, vous devez dépendre du "
open
" builtinlistdir
"," peut-être "isdir
" ou "os.walk
" ou "shutil.copy
". Peut-être "os.path.join
" aussi. Sans parler du fait que vous avez besoin d'une chaîne passée un argument pour identifier le fichier réel. Jetons un coup d'œil à l'implémentation complète qui copiera "index.tpl" de chaque répertoire dans "index.html":La fonction "sous-répertoires" ci-dessus peut fonctionner sur n'importe quel
FilePath
objet semblable. Ce qui signifie, entre autres, desZipPath
objets. MalheureusementZipPath
est actuellement en lecture seule, mais il pourrait être étendu pour prendre en charge l'écriture.Vous pouvez également transmettre vos propres objets à des fins de test. Afin de tester les API utilisant os.path suggérées ici, vous devez singe avec des noms importés et des dépendances implicites et généralement effectuer de la magie noire pour que vos tests fonctionnent. Avec FilePath, vous faites quelque chose comme ceci:
la source
Je viens d'écrire du code pour déplacer les machines virtuelles vmware, et j'ai fini par utiliser
os.path
etshutil
pour effectuer la copie de fichiers entre les sous-répertoires.Ce n'est pas très élégant, mais ça marche.
la source
Voici une façon:
la source
Je dois mentionner la bibliothèque path.py , que j'utilise très souvent.
Récupérer les sous-répertoires immédiats devient aussi simple que cela:
my_dir.dirs()
L'exemple de travail complet est:
la source
La fonction suivante peut être appelée comme:
get_folders_in_directories_recursively (directory, index = 1) -> donne la liste des dossiers du premier niveau
get_folders_in_directories_recursively (directory) -> donne tous les sous-dossiers
la source
La
child_dirs
fonction prend un chemin dans un répertoire et retourne une liste des sous-répertoires immédiats qu'il contient .la source
la source
Un liner utilisant pathlib:
la source