Vous savez déjà que les
fonctions Python sont des objets. Ce
que vous ne savez pas, c’est que vous pouvez obtenir une référence à
une fonction sans connaître son nom avant l’exécution, à l’aide de la
fonction getattr.
Exemple 4.10. Présentation de getattr
>>> li = ["Larry", "Curly"]>>> li.pop<built-in method pop of list object at 010DF884>>>> getattr(li, "pop")<built-in method pop of list object at 010DF884>>>> getattr(li, "append")("Moe")>>> li["Larry", "Curly", "Moe"]>>> getattr({}, "clear")<built-in method clear of dictionary object at 00F113D4>>>> getattr((), "pop")Traceback (innermost last):
File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'pop'
Ceci retourne une référence à la méthode
pop de la liste. Ce n’est pas un appel à la
méthode pop, un appel se ferait par
li.pop(). C’est la méthode elle-même.
Ceci retourne également une référence à la méthode
pop, mais cette fois ci le nom de la méthode
est passé comme argument de la fonction
getattr. getattr est une
fonction prédéfinie extrèmement utile qui retourne n’importe quel
attribut de n’importe quel objet. Ici, l’objet est une liste et
l’attribut est la méthode pop.
Au cas où vous ne voyez pas à quel point c’est utile, regardez
ceci : la valeur de retour de getattrest la méthode, que vous pouvez alors appeler
comme si vous aviez tapé li.append("Moe")
directement. Mais vous n’avez pas appelé la fonction directement,
vous avez passé le nom de la fonction comme paramètre sous forme
de chaîne.
getattr fonctionne aussi avec les dictionnaires.
En théorie, getattr pourrait
fonctionner avec les tuples, mais les tuples n’ont pas de
méthodes et getattr déclenchera une
exception quel que soit le nom d’attribut que vous lui
donnez.
4.4.1. getattr et les modules
getattr n’est pas seulement fait pour les
types prédéfinis, il fonctionne aussi avec les modules.
Ceci retourne une référence à la fonction
buildConnectionString du module odbchelper, que nous avons étudié
au Chapitre 2, Votre premier programme Python. (L’adresse hexadécimale qui
s’affiche est spécifique à ma machine, votre sortie sera
différente.)
A l’aide de getattr, nous pouvons
obtenir la même référence à la même fonction. En général,
getattr(objet,
"attribut") est équivalent à
objet.attribut.
Si objet est un module, alors
attribut peut être toute chose définie
dans le module : une fonction, une classe ou une variable
globale.
Voici ce que nous utilisons dans la fonction
info. object est passé en
argument à la fonction, method est une chaîne,
le nom de la méthode ou de la fonction.
Dans ce cas, method est le nom d’une
fonction, ce que nous prouvons en obtenant son type.
Puisque method est une fonction, elle est
callable
(appelable).
4.4.2. getattr comme sélecteur
Une utilisation usuelle de getattr est dans le rôle de sélecteur. Par exemple, si vous avez un programme qui peut produire des données dans différents formats,
vous pouvez définir des fonctions différentes pour chaque format de sortie et utiliser une fonction de sélection pour appeler
celle qui convient.
Par exemple, imaginons un programme qui affiche des statistiques de consultations d'un site Web aux formats HTML, XML et texte simple. Le choix du format de sortie peut être spécifié depuis la ligne de commande ou stocké dans un fichier de
configuration. Un module statsout définit trois fonctions, output_html, output_xml et output_text. Ensuite, le programme principal définit une fonction de sortie unique, comme ceci :
Exemple 4.12. Création d'un sélecteur avec getattr
La fonction output prend un argument obligatoire, data et un argument optionnel, format. Si format n'est pas spécifié, il a la valeur par défaut text ce qui appelera la fonction de sortie en texte simple.
Nous concaténons l'argument format à "output_" pour produire un nom de fonction et allons chercher cette fonction dans le module statsout. Cela nous permet d'étendre simplement le programme plus tard pour supporter d'autres formats de sortie, sans changer la
fonction de sélection. Il suffit d'ajouter une autre fonction à statsout nommée, par exemple, output_pdf et de passer "pdf" comme format à la fonction output.
Maintenant, nous pouvons simplement appeler la fonction de sortie comme toute autre fonction. La variable output_function est une référence à la fonction appropriée du module statsout.
Avez vous vu le problème dans l'exemple précédent ? Il y a un couplage très lâche entre chaînes et fonctions et il n'y a aucune
vérification d'erreur. Que se passe-t-il si l'utilisateur passe un format pour lequel aucune fonction correspondante n'est
définie dans le module statsout? Et bien, getattr retournera None, qui sera assigné à output_function au lieu d'une fonction valide et à la ligne suivante, qui tente d'appeler cette fonction inexistante, plantera et déclenchera
une exception. C'est un problème.
Heureusement getattr prend un troisième argument optionnel, une valeurpar défaut.
Cet appel de fonction est assuré de fonctionner puisque nous avons ajouté un troisième argument à l'appel à getattr. Le troisième argument est une valeur par défaut qui est retournée si l'attribut ou la méthode spécifié par le second argument
n'est pas trouvé.
Comme vous pouvez le voir, getattr est très puissant. C'est le coeur même de l'introspection et vous en verrez des exemples encore plus puissants dans des prochains
chapitres.