Prenons un exemple. Vous avez une classe Rectangle qui a deux attributs : longueur et largeur. Vous pouvez les redéfinir à volonté, bien.

>>> class Rectangle(object):
...     def __init__(self, longueur, largeur):
...             self.longueur = longueur
...             self.largeur = largeur
... 
>>> a = Rectangle(10, 1)
>>> a.longueur
10
>>> a.longueur = 15
>>> a.longueur
15

Mais s'il vous prend l'idée subite et stupide d'ajouter un attribut aire, comment allez-vous faire pour que sa valeur soit toujours exacte ? Si vous modifiez la longueur du rectangle, il y aura un problème.

>>> a.aire = a.longueur * a.largeur
>>> a.aire
15
>>> a.largeur = 3
>>> a.aire
15

Bien que la largueur du rectangle ait changée, l'aire n'a pas bougé d'un poil. C'est un comportement normal (c'est une simple variable), mais ce n'est pas le comportement souhaité. On peut utiliser une fonction trouverAire() ou aire(), mais c'est nettement moins sex' qu'une variable non ?

Mais Python nous offre (comme d'autres langages) une solution adaptée à notre problème : les properties. Grâce au type prédéfini property, on va pouvoir créer un attribut spécial de la classe Rectangle, qui sera (du côté utilisateur de la classe) identique à un attribut simple. Cet attribut est spécial dans le sens où, lorsqu'on veut accéder à sa valeur, la modifier ou le supprimer, on passe part des fonctions. Même si vous vous en foutez sûrement, voici la signature de property

property(fget = None, fset = None, fdel = None, doc = None) -> property attribute

fget est appelé quand on demande la valeur de l'attribut, fset lorsqu'on affecte à l'attribut une valeur et fdel quand on veut supprimer l'attribut. doc est l'éventuelle docstring de l'attribut.

Si on reprend notre exemple de rectangles, lorsque l'utilisateur va demander la valeur de l'aire de notre rectangle, Python appellera une fonction prédéfinie qui va renvoyer, après calcul, la valeur de l'aire. Cette valeur sera toujours correcte, puisque recalculée à chaque demande. Exemple :

>>> class Rectangle(object):
...     def __init__(self, largeur, hauteur):
...             self.largeur = largeur
...             self.hauteur = hauteur
...     def _getAire(self):
...             return self.largeur * self.hauteur
...     aire = property(_getAire)
... 
>>> a = Rectangle(10, 5)
>>> a.aire
50
>>> a.largeur = 3
>>> a.aire
15

Ici, chaque instance la classe Rectangle a un attribut aire en lecture seule (si un des trois paramètres n'est pas donné, alors l'opération correspondante lève une exception), recalculé à chaque demande.