Outils pour utilisateurs

Outils du site


decorateurs_property

Modèles de code pour utiliser les @property

Problématique

Avec les classes “nouveau style”, utiliser “property” est intéressant parce que ça permet en même temps:

  • de manipuler (lecture/écriture/destruction) des attributs comme s'ils étaient 'normaux' (toto.x = 123, y = toto.x, del toto.x)
  • d'obliger ces manipulations d'attribut à passer par des méthodes définies dans la classe
  • voire, d'empêcher certaines de ces manipulations si les méthodes correspondantes n'existent pas

Voir http://docs.python.org/library/functions.html#property

Codes proposés

Parmi les différents codes possibles, j'en ai retenu 2:

Version avec décorateur:

def Property(func):
    return property(**func()) 
 
class Maclasse(object):
 
    def __init__(self, x):
        self._x = x
 
    @Property
    def x():
 
        doc = "docstring de x"
 
        def fget(self):
            return self._x
 
        def fset(self, x):
            self._x = x
 
        def fdel(self):
            del self._x
 
        return locals()

Version sans décorateur:

class Maclasse(object):
 
    def __init__(self, x):
        self._x = x
 
    def x():
        doc = "docstring de x"
 
        def fget(self):
            return self._x
 
        def fset(self, x):
            self._x = x
 
        def fdel(self):
            del self._x
 
        return locals()
 
    x = property(**x())

Exemple d'utilisation

Pour bien comprendre comment ça marche, on va créer une classe Test avec un attribut x qui sera manipulé par property.

on va ajouter des 'print' pour signaler l'appel aux fonctions qui vont agir sur x.

Et on va retirer la méthode de destruction de l'attribut:

class Test(object):
 
    def __init__(self, x):
        self._x = x
 
    def x():
        doc = "docstring de x"
 
        def fget(self):
            print "appel à fget"
            return self._x
 
        def fset(self, x):
            print "appel à fset"
            self._x = x
 
        return locals()
 
    x = property(**x())

Essayons maintenant des appels:

a = Test(5)
 
print a.x
appel à fget
5
 
a.x = 9
appel à fset
 
print a.x
appel à fget
9
 
del a.x
# genère une exception: "AttributeError: can't delete attribute" puisque la méthode fdel n'existe pas 

On voit bien que les opérations de lecture (print a.x) et d'écriture (a.x=9) passent obligatoirement par les méthodes fget et fset, alors que de l'extérieur de la classe, on réalise ces opérations comme si x était un attribut 'normal'.

On a omit de définir ici la méthode fdel (ce qui interdit la destruction de x), mais on aurait pu aussi omettre de définir la méthode fset (ce qui interdirait tout changement de valeur de x), ou même la méthode fget (ce qui interdirait toute lecture).

Pour le docstring de x, son accès à partir de l'extérieur est un peu plus complexe, parce qu'il appartient à la classe, et pas à l'instance de classe. On peut donc le retrouver par l'une de ces 2 instructions:

print Test.x.__doc__
docstring de x
 
print a.__class__.x.__doc__
docstring de x


Amusez-vous bien!

decorateurs_property.txt · Dernière modification: 2011/04/06 10:25 de tyrtamos

Outils de la page