A nouveau, tous les dominos sont en place. Nous avons vu comment
chaque ligne de code fonctionne. Maintenant prenons un peut de recul
pour voir comment tout cela s’assemble.
Exemple 6.21. listDirectory
def listDirectory(directory, fileExtList): "get list of file info objects for files of particular extensions"
fileList = [os.path.normcase(f)
for f in os.listdir(directory)]
fileList = [os.path.join(directory, f)
for f in fileList
if os.path.splitext(f)[1] in fileExtList] def getFileInfoClass(filename, module=sys.modules[FileInfo.__module__]): "get file info class from filename extension"
subclass = "%sFileInfo" % os.path.splitext(filename)[1].upper()[1:] return hasattr(module, subclass) and getattr(module, subclass) or FileInfo return [getFileInfoClass(f)(f) for f in fileList]
listDirectory est l’attraction
principale de ce module. Elle prend un répertoire (c:\music\_singles\ dans mon cas) et
une liste d’extensions intéressantes (comme
['.mp3']) et elle retourne une liste
d’instances de classe qui se comportent comme des dictionnaires et
qui contiennent des métadonnées concernant chaque fichier
intéressant de ce répertoire. Et elle le fait en une poignée de
ligne simples et directes.
Comme nous l’avons vu dans la section précédente, cette ligne de
code permet d’obtenir une liste de noms de chemin complets de tous
les fichiers de directory qui ont une extension
de fichier intéressante (comme spécifiée par
fileExtList).
Les programmeurs Pascal à
l’ancienne les connaissent bien, mais la plupart des gens me
jettent un regard vide quand je leur dit que
Python supporte les fonctions
imbriquées -- littéralement une fonction à l’intérieur
d’une fonction. La fonction imbriquée
getFileInfoClass peut seulement être appelée
de la fonction dans laquelle elle est définie,
listDirectory. Comme pour toute autre
fonction, vous n’avez pas besoin d’une déclaration d’interface ou
de quoi que ce soit d’autre, définissez juste la fonction et
écrivez-la.
Maintenant que vous avez vu le module os, cette ligne devrait être
plus compréhensible. Elle obtient l’extension du fichier
(os.path.splitext(filename)[1]), la force en
majuscules (.upper()), découpe le point
([1:]) et construit un nom de classe en
formatant la chaîne. Donc,
c:\music\ap\mahadeva.mp3 devient
.mp3, puis .MP3, puis
MP3 et enfin
MP3FileInfo.
Ayant construit le nom de la classe qui doit manipuler ce
fichier, nous vérifions si cette classe existe dans ce module. Si
c’est le cas, nous retournons la classe, sinon, nous retournons la
classe de base, FileInfo. C’est un point
très important : cette fonction retourne une
classe. Pas une instance de classe, mais la classe
elle-même.
Pour chaque fichier dans notre liste de «fichiers
intéressants» (fileList), nous appelons
getFileInfoClass avec le nom de fichier
(f). Appeler
getFileInfoClass(f) retourne une classe, nous
ne savons pas exactement laquelle mais cela ne nous intéresse pas.
Nous créons alors une instance de cette classe (quelle qu’elle
soit) et passons le nom du fichier (encore f),
à la méthode __init__. Comme nous l’avons vu
auparavant dans ce
chapitre, la méthode __init__ de
FileInfo définit
self["name"], ce qui déclenche
__setitem__, qui est redéfini dans la classe
descendante (MP3FileInfo) comme une
fonction traitant le fichier de manière à en extraire les
métadonnées. Nous faisons cela pour tous les fichiers intéressants
et retournons une liste des instances ainsi créées.
Notez que listDirectory est complètement
générique. Il ne sait pas à l’avance quels types de fichiers iI va
obtenir, ou quelles sont les classes qui pourraient triter ces fichiers.
Il inspecte le répertoire à la recherche de fichiers à traiter, puis
recourt à l’introspection sur son propre module pour voir quelles
classes de traitement (comme MP3FileInfo) sont
définies. Vous pouvez étendre ce programme pour gérer d’autres types de
fichiers simplement en définissant une classe portant un nom approprié :
HTMLFileInfo pour les fichiers
HTML, DOCFileInfo pour les
fichiers .doc de Word,
etc. listDirectory les prendra tous en charge, sans
modification, en se déchargeant du traitement proprement dit sur les
classes appropriées et en assemblant les résultats.