2009-04-28 4 views
89

J'essaye d'écrire un simple script Python qui va copier un index.tpl dans index.html dans tous les sous-répertoires (à quelques exceptions près). Je m'embourbe en essayant d'obtenir la liste des sous-répertoires.Comment obtenir tous les sous-répertoires immédiats en Python

+8

Vous pouvez constater que la réponse acceptée à cette question précédente SO résout le problème: http://stackoverflow.com/questions/120656/directory-listing-in-python –

Répondre

154
import os 
def get_immediate_subdirectories(a_dir): 
    return [name for name in os.listdir(a_dir) 
      if os.path.isdir(os.path.join(a_dir, name))] 
8

os.walk est votre ami dans cette situation.

Droit de la documentation:

promenade() génère les noms de fichiers dans une arborescence de répertoires, en marchant l'arbre soit de haut en bas ou de bas en haut. Pour chaque répertoire de l'arborescence racine du répertoire top (y compris le sommet lui-même), il donne un triplet (dirpath, dirnames, noms de fichiers).

+1

Sachez simplement que si vous voulez seulement les sous-répertoires de premier niveau s'échappent alors de l'itération os.walk après le premier ensemble de valeurs de retour. – yoyo

6

En utilisant le module CheminFichier Twisted:

from twisted.python.filepath import FilePath 

def 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é à ce que les avantages de l'utilisation des bibliothèques de Twisted pour cela est, je vais aller un peu au-delà de la question originale ici.


Il y a some improved documentation dans une branche qui explique les avantages de CheminFichier; vous pourriez vouloir lire cela.

Plus spécifiquement dans cet exemple: contrairement à la version de bibliothèque standard, cette fonction peut être implémentée avec sans les importations. La fonction "subdirs" est totalement générique, en ce sens qu'elle ne fonctionne que sur son argument. Afin de copier et déplacer les fichiers en utilisant la bibliothèque standard, vous devez dépendre du "open" intégré, "listdir", peut-être "isdir" ou "os.walk" ou "shutil.copy". Peut-être "os.path.join" aussi. Sans oublier le fait que vous avez besoin d'une chaîne passée un argument pour identifier le fichier réel. Jetons un coup d'oeil à la pleine application qui copie « de index.tpl » à « index.html » de chaque répertoire:

def copyTemplates(topdir): 
    for subdir in subdirs(topdir): 
     tpl = subdir.child("index.tpl") 
     if tpl.exists(): 
      tpl.copyTo(subdir.child("index.html")) 

La fonction « subdirs » ci-dessus peuvent travailler sur tout FilePath objet -comme. Ce qui signifie, entre autres, ZipPath objets. Malheureusement, ZipPath est en lecture seule pour le moment, 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 utiliser des noms importés et des dépendances implicites et effectuer généralement de la magie noire pour que vos tests fonctionnent. Avec CheminFichier, vous faites quelque chose comme ceci:

class MyFakePath: 
    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(...)) 
+0

Comme j'ai peu d'expérience avec Twisted, j'accueille toujours des informations et des exemples supplémentaires; cette réponse est agréable à voir pour cela. Cela dit, étant donné que cette approche semble exiger beaucoup plus de travail que l'utilisation des modules python intégrés, et une installation Twisted, y a-t-il des avantages à utiliser ceci que vous pourriez ajouter à la réponse? –

+1

La réponse de Glyph a probablement été inspirée par le fait que TwistedLore utilise également des fichiers .tpl. – Constantin

+0

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 de langues après tout). Bon à savoir. –

1

est ici une façon:

import os 
import shutil 

def copy_over(path, from_name, to_name): 
    for path, dirname, fnames in os.walk(path): 
    for fname in fnames: 
     if fname == from_name: 
     shutil.copy(os.path.join(path, from_name), os.path.join(path, to_name)) 


copy_over('.', 'index.tpl', 'index.html') 
+0

-1: ne fonctionnera pas, car shutil.copy copiera dans le répertoire actuel, de sorte que vous finirez par écraser 'index.html' dans le répertoire actuel une fois pour chaque 'index.tpl' que vous trouverez dans l'arborescence du sous-répertoire . – nosklo

+0

Correction du code, merci! –

2

Je viens d'écrire un code pour déplacer des machines virtuelles vmware autour, et a fini par utiliser pour réaliser la copie de fichiers os.path et shutil entre sous-répertoires.

def copy_client_files (file_src, file_dst): 
    for file in os.listdir(file_src): 
      print "Copying file: %s" % file 
      shutil.copy(os.path.join(file_src, file), os.path.join(file_dst, file)) 

Ce n'est pas très élégant, mais ça marche.

13
import os, os.path 

Pour (chemin complet) sous-répertoires immédiats dans un répertoire:

def SubDirPath (d): 
    return filter(os.path.isdir, [os.path.join(d,f) for f in os.listdir(d)]) 

Pour obtenir les derniers (les plus récents) sous-répertoire:

def LatestDirectory (d): 
    return max(SubDirPath(d), key=os.path.getmtime) 
46

Pourquoi personne n'a mentionné glob? glob vous permet d'utiliser l'extension de chemin Unix-style, et est mon aller à la fonction pour presque tout ce qui doit trouver plus d'un nom de chemin. Il est très facile:

from glob import glob 
paths = glob('*/') 

Notez que glob retournera le répertoire avec la barre oblique finale (comme unix se) alors que la plupart des solutions basées path omettra la barre oblique finale.

+2

Bonne solution, simple et fonctionne. Pour ceux qui ne veulent pas ce slash final, il peut utiliser 'paths = [p.replace ('/', '') pour p in glob ('* /')]'. –

+3

Il peut être plus sûr de simplement couper le dernier caractère avec '[p [: - 1] pour p dans les chemins]', car cette méthode remplacera également toutes les barres obliques échappées du nom de fichier (pas communes). – ari

+2

Encore plus sûr, utilisez la bande ('/') pour supprimer les barres obliques.De cette façon, vous ne coupez pas les caractères qui ne sont pas des barres obliques –

9

Cochez la case "Getting a list of all subdirectories in the current directory".

est ici une version Python 3:

import os 

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

print(dir_list) 
+0

Il serait plus clear si 'file_list' a été remplacé par' dir_list', car '[1]' retourne la liste des répertoires. – wisbucky

+0

@wisbucky point juste, j'ai mis à jour ma réponse. –

+1

** Extrêmement intelligent. ** Alors que l'efficacité n'a pas d'importance (_... elle fait totalement_), je suis curieux de savoir si ceci ou l'expression du générateur glob-based '(s.rstrip ("/") pour s dans glob (parent_dir + "* /")) 'est plus rapide. Mon soupçon intuitif est qu'une solution 'os.walk()' basée sur 'stat()' * devrait * être * profondément plus rapide que la globalisation de type shell. Malheureusement, il me manque la volonté de «timeit» et de le découvrir. –

6

Cette méthode fait bien tout en une seule fois.

from glob import glob 
subd = [s.rstrip("/") for s in glob(parent_dir+"*/")]