You are here: Sommaire > Plongez au coeur de Python > Traitement du HTML > locals et globals | << >> | ||||
Plongez au coeur de PythonDe débutant à expert |
Laissons de coté le traitement du HTML une minute pour parler de la manière dont Python gère les variables. Python a deux fonctions prédéfinies permettant d’accéder aux variables locales et globales sous forme de dictionnaire : locals et globals.
Vous vous rappelez de locals ? Vous l'avez vu pour la première fois ici :
def unknown_starttag(self, tag, attrs): strattrs = "".join([' %s="%s"' % (key, value) for key, value in attrs]) self.pieces.append("<%(tag)s%(strattrs)s>" % locals())
Mais vous ne pouvez rien apprendre sur locals pour le moment. Vous devez d'abord apprendre les espaces de noms. C’est un concept un peu aride mais important, lisez donc attentivement.
Python utilise ce que l’on appelle des espaces de noms pour suivre les variables. Un espace de noms est semblable a un dictionnaire dans lequel les clés sont les noms des variables et les valeurs du dictionnaire sont les valeurs des variables. En fait, on accède à un espace de noms comme à un dictionnaire Python, comme nous le verrons un peu plus loin.
A n’importe quel point dans un programme Python, il y a plusieurs espaces de noms disponibles. Chaque fonction a son propre espace de noms, appelé espace de noms local, qui suit les variables de la fonction, y compris ses arguments et les variables définies localement. Chaque module a son propre espace de noms, appelé l’espace de noms global, qui suit les variables du module, y compris les fonctions, les classes, les modules importés et les variables et constantes du module. Il y a également un espace de noms prédéfini, accessible de n’importe quel module et qui contient les fonctions et exceptions du langage.
Lorsqu’une ligne de code demande la valeur d’une variable x, Python recherche cette variable dans tous les espaces de noms disponibles dans l’ordre suivant :
Si Python ne trouve x dans aucun de ces espaces de noms, il abandonne et déclenche une exception NameError avec le message There is no variable named 'x', que vous avez vu tout au début au chapitre 1, mais à ce moment là vous ne pouviez pas savoir tout le travail que Python fait avant de vous renvoyer cette erreur.
Python 2.2 a introduit une
modification légère mais importante qui affecte l’ordre de recherche
dans les espaces de noms : les portées imbriquées. Dans les versions
précédentes de Python, lorsque vous
référenciez une variable dans une fonction imbriquée ou une fonction lambda,
Python recherchait la variable dans l’espace
de noms de la fonction (imbriquée ou lambda) en
cours, puis dans l’espace de noms du module.
Python 2.2 recherche la variable dans
l’espace de noms de la fonction (imbriquée ou
lambda) en cours, puis dans l’espace de
noms de la fonction parente, puis dans l’espace de noms du
module. Python 2.1 peut adopter l'un ou l'autre de ces
comportements, par défaut il fonctionne comme
Python 2.0, mais vous pouvez ajouter la
ligne de code suivante au début de vos modules pour les faire
fonctionner comme avec Python 2.2 :from __future__ import nested_scopes |
Vous êtes perdu ? Ne vous inquiétez pas, je vous promet que c'est très utile. Comme beaucoup de chose en Python, les espaces de noms sont directement accessibles durant l’exécution. L’espace de noms local est accessible par la fonction prédéfinie locals et l’espace de noms global (du module) est accessible par la fonction prédéfinie globals.
>>> def foo(arg): ... x = 1 ... print locals() ... >>> foo(7) {'arg': 7, 'x': 1} >>> foo('bar') {'arg': 'bar', 'x': 1}
Ce que fait locals pour l’espace de noms local (de la fonction), globals le fait pour l’espace de noms global (du module). globals est cependant plus intéressant, parce que l’espace de noms d’un module est plus intéressant. L’espace de noms d’un module ne comprend pas seulement les variables et constantes du module mais aussi l’ensemble des fonctions et classes définies dans le module. De plus, il contient tout ce qui a été importé dans le module.
Vous rappelez-vous de la différence entre from module import et import module ? Avec import module, le module lui-meme est importé mais il garde son propre espace de noms, c’est pourquoi vous devez utiliser le nom du module pour accéder à ses fonctions ou attributs : module.fonction. Mais avec from module import, vous importez des fonctions et des attributs spécifiques d’un autre module dans votre propre espace de noms, c’est pourquoi vous y accédez directement sans référence au module dont ils viennent. Avec la fonction globals, vous pouvez voir ce qui se passe.
Regardez me bloc de code suivant, à la fin de BaseHTMLProcessor.py:
if __name__ == "__main__": for k, v in globals().items(): print k, "=", v
Ne soyez pas intimidé, vous avez déjà vu tout cela. La fonction globals retourne un dictionnaire et nous parcourons le dictionnaire à l’aide de la méthode items et de l’assignement multiple. Le seul élément nouveau ici est la fonction globals. |
Maintenant, exécuter le programme de la ligne de commande nous donne la sortie suivante (notez qu'elle peut être légèrement différente en fonction de votre plate-forme et de l'endroit où vous avez installé Python) :
c:\docbook\dip\py> python BaseHTMLProcessor.py
SGMLParser = sgmllib.SGMLParser htmlentitydefs = <module 'htmlentitydefs' from 'C:\Python23\lib\htmlentitydefs.py'> BaseHTMLProcessor = __main__.BaseHTMLProcessor __name__ = __main__ ... rest of output omitted for brevity...
SGMLParser a été importé de sgmllib, en utilisant from module import. Cela veut dire qu’il a été importé directement dans l’espace de noms du module, et nous le voyons donc s’afficher. | |
Comparez avec htmlentitydefs, qui a été importé avec import. Le module htmlentitydefs lui-même est dans notre espace de noms, mais la variable entitydefs définie dans htmlentitydefs ne l’est pas. | |
Ce module ne définit qu’une classe, BaseHTMLProcessor et la voici. Notez que la valeur est ici la classe elle-même et non une instance quelconque de cette classe. | |
Vous rappelez-vous de l’astuce if __name__ ? Lorsque vous exécutez un module (plutôt que de l’importer d’un autre module), l’attribut prédéfini __name__ a une valeur spéciale, __main__. Comme nous avons exécuté ce module comme un programme de la ligne de commande, __name__ vaut __main__, c’est pourquoi notre petit code de test qui affiche globals est exécuté. |
A l’aide des fonctions locals et globals, vous pouvez obtenir la valeur d’une variable quelconque dynamiquement, en fournissant le nom de la variable sous forme de chaîne. C’est une fonctionnalité semblable à celle de la fonction getattr, qui vous permet d’accéder à une fonction quelconque dynamiquement en fournissant le nom de la fonction sous la forme d’une chaîne. |
Il y a une différence importante entre locals et globals que vous devez apprendre maintenant pour ne pas qu’elle vous joue des tours plus tard. Elle vous jouera des tours de toute manière mais au moins vous vous souviendrez que vous l’avez appris.
def foo(arg): x = 1 print locals() locals()["x"] = 2 print "x=",x z = 7 print "z=",z foo(3) globals()["z"] = 8 print "z=",z
<< Présentation de BaseHTMLProcessor.py |
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
Formatage de chaînes à l’aide d’un dictionnaire >> |