Page suivante   Page précédente   Table des matières  

6. Introduction à la programmation orientée objet en Python

Par Micheal Orr, mso@mso.oz.net

On a demandé à Michael Williams s'il pouvait écrire des version en Java et en Python de son article Introduction à la programmation orientée objet en C++. Voici la version en Python de son code. De plus, je commenterais les différences entre le C++ et le Python. Y aura-t-il un volontaire pour écrire la version en Java ?

Je suppose que vous connaissez les bases du Python. Si non, jetez un coup d'oeil+ à cet excellent dictaciel (qui est en anglais, pour un dictaciel en français allez plutôt voir du côté de celui-ci), et le reste de la documentation à http://www.python.org/doc.

6.1 Des maisons, encore des maisons !

Pour représenter la maison de Michael (de la section C'est classe ! de son article sur le C++), vous pouvez utiliser le code ci-dessous : ( version texte)


#! /usr/bin/python
""" maison.py -- Un programme de maison
C'est une chaîne de documentation encadrée par des doubles apostrophes triples
"""

class Maison:
        pass

ma_maison = Maison()
ma_maison.numero = 40
ma_maison.pieces = 8
ma_maison.jardin = 1

print "Ma maison a le numéro :", ma_maison.numero, "."
print "Elle a", ma_maison.pieces, "pièces."
if ma_maison.jardin:
        texte_jardin = "a un"
else:
        texte_jardin = "n'a pas de"
print "Elle", texte_jardin, "jardin."

Si nous le lançons, nous obtenons l'affichage suivant :


Ma maison a le numéro : 40 .
Elle a 8 pièces.
Elle a un jardin.

Que peux donc bien faire ce programme ? Tout d'abord, nous déclarons ce qu'est une maison générique dans le corps class. pass veut dire « ne rien faire » et est obligatoire, sinon le corps serait vide. Puis, nous créons une instance, c'est-à-dire une maison en particulier, en appelant le nom de la classe, de la même manière que l'on procéderais avec une fonction. Enfin, la maison est ensuite emmagasinée dans la variable ma_maison.

Cette maison n'a au départ aucun attribut ­ si nous interrogions ma_maison.numero avant de l'avoir fixée, nous obtiendrions une erreur AttributeError. Les trois prochaines lignes fixent et créent les attributs. C'est une des différences entre les langages : les instances du Java démarrent avec un nombre fixé d'attributs qui ne peut en aucun cas changer (bien que leurs valeurs puissent changer), mais les instances du Python démarrent sans attribut, et vous pouvez ajouter ou supprimer des attributs (ou changer leur type) à tout moment. Cela permet au Python d'être plus flexible dans certaines situations dynamiques.

Nous pouvons initialiser l'instance lors de la création en incluant une méthode spécifique nommée __init__. (Une méthode étant une fonction qui « appartient » à une classe.) Voici ce programme: ( version texte)


#! /usr/bin/python
""" maison2.py -- Une autre maison.
"""

class Maison:
        def __init__(self, numero, pieces, jardin):
                self.numero = numero
                self.pieces = pieces
                self.jardin = jardin

ma_maison = Maison(20, 1, 0)

print "Ma maison a le numéro :", ma_maison.numero, "."
print "Elle a", ma_maison.pieces, "pièces."
if ma_maison.jardin:
        texte_jardin = "a un"
else:
        texte_jardin = "n'a pas de"
print "Elle", texte_jardin, "jardin."

ce qui affiche :


Ma maison a le numéro : 20 .
Elle a 1 pièces.
Elle n'a pas de jardin.

Puisque la classe a une méthode __init__, elle est appelée automatiquement lors de la création d'une instance. Les arguments de Maison sont en fait ceux d'__init__. Bien que la plupart des programmes ne le fassent pas, vous pouvez tout aussi bien appeler __init__ autant de fois que vous le voulez : ma_maison.__init__(55, 14, 1), ce qui oblige l'objet à « se réinitialiser lui-même ».

Notez qu'__init__ est déclarée avec un argument supplémentaire, self. Mais nous n'en tenons pas compte lorsque nous appelons la méthode. Toutes les méthodes du Python fonctionnent ainsi. self est en fait l'instance elle-même, et le Python la met à disposition de la fonction par derrière. Vous devez le mentionner explicitement car c'est le seul moyen qui permet à la méthode d'accéder aux attributs de l'instance et des autres méthodes. Au sein de la méthode, self.pieces fait référence à la variable d'instance, mais pieces fait référence à la variable locale pieces. Les variables locales disparaissent bien entendu lorsque la méthode se termine. L'utilisation de self par le Python est parallèle à celle du Perl aussi bien que celle d'autres langages OO (Orienté Objet).

Michael ne vous l'avait pas précisé mais le C++ a un pointeur this qui fonctionne de la même manière que self du Python. En revanche en C++ vous n'avez pas à taper this->maison s'il n'y a pas de variable locale maison et vous ne tapez jamais this sur la ligne de déclaration de méthode. En d'autres termes, le C++ (et le Java) fonctionne de la même manière que le Python et le Perl, ils ne font que le cacher au programmeur.

En fait, self est juste une convention. Vous pouvez utiliser me à la place de this si vous préférez. Ma préférence va à me, mais je reste fidèle à self car si quelqu'un doit maintenir mon travail un jour, ce lui sera plus facile de lire mon code. A l'opposée, la variable this du C++ est « magique » et ne peut donc pas être renommée.

Dans le programme en C++, jardin est un attribut booléen. Le Python n'a pas d'attribut booléen c'est pourquoi nous utilisons à la place un entier. L'expression ma_maison.jardin est vraie si l'attribut est à 1 (ou n'importe quel nombre non-nul ou n'importe quelle valeur non-vide).

6.2 Ne soyez pas si carré !

Cette section correspond à la section Fonctions membres de l'article de William. Je préfère le terme « méthode » à celui de « fonction membre » comme la plupart des pythonistes. square.c de Michael ressemblerait à quelque chose dans ce style en Python : ( version texte)


#! /usr/bin/python
"""rectangle.py -- Faisons parlez de nous avec ce rectangle
"""

class Rectangle:
        def __init__(self, longueur, largeur):
                self.longueur = longueur
                self.largeur = largeur
                
        def aire(self):
                return self.longueur * self.largeur
                
mon_rectangle = Rectangle(5, 2)
print mon_rectangle.aire()

Ce qui affiche :


10

La fonction aire devrait s'expliquer d'elle-même car elle fonctionne exactement de la même manière qu'__init__. Répétons-le, tous les selfs de rectangle.py sont absolument nécessaires. J'ai également choisi de mettre en oeuvre une méthode __init__ plutôt que de fixer les attributs plus tard, car c'est ce que font la plupart des pythonistes.

6.3 Déclaration de fonctions en dehors de la déclaration de la classe

Rien à dire ici. Le Python ne permet pas de déclarer une méthode en dehors de la classe. Bien entendu, cela ne s'applique pas aux fonctions ordinaires (en dehors de toute classe).

6.4 Public ou privé ?

Il n'y a pas grand-chose à ajouter. Tous les attributs et les méthodes de Python sont publiques. Vous pouvez émuler les attributs et les méthodes privées via la bidouille du double-souligné, mais la plupart des pythonistes ne l'utilise pas, comptant sur les autres programmeurs pour ne pas abuser des APIs des classes.

6.5 Les constructeurs de classe

La méthode __init__ est le constructeur.

6.6 Les tableaux et les classes

L'exemple avec les tableaux de Williams ne peux être codé litéralement à cause des différences entre langages, mais voici un équivalent : ( version texte)


#! /usr/bin/python
"""personne.py -- Un exemple avec plusieurs personnes
"""

class Personne:
        def __init__(self, age, numero_maison):
                self.age = age
                self.numero_maison = numero_maison

Alex = []
for i in range(5):
        objet = Personne(i, i)
        Alex.append(objet)
        
print "L'âge d'Alex[3] est de", Alex[3].age, "ans."
print

for sous_Alex in Alex:
    print "Son âge est de", sous_Alex.age,  "ans."
    print "Le numéro de sa maison est le", sous_Alex.numero_maison,"."

Ce qui affiche :


L'âge d'Alex[3] est de 3 ans.

Son âge est de 0 ans.
Le numéro de sa maison est le 0 .
Son âge est de 1 ans.
Le numéro de sa maison est le 1 .
Son âge est de 2 ans.
Le numéro de sa maison est le 2 .
Son âge est de 3 ans.
Le numéro de sa maison est le 3 .
Son âge est de 4 ans.
Le numéro de sa maison est le 4 .

Le Python n'a pas d'équivalent au personne_Alex[5] du programme en C++ qui crée un tableau de cinq instances d'un seul coup. A la place, nous créons une liste vide et nous utilisons une boucle for (qui fixe respectivement i à 0, 1, 2, 3 et 4) pour la remplir. Cet exemple montre une boucle parcourant une liste par son numéro d'index, une autre qui récupère chaque élément directement dans la liste, et une instruction print qui accède à un élément par son numéro d'index.

Copyright 2000, Michael Orr. Paru dans le numéro 56 de la Linux Gazette d'Août 2000.

Traduction française de Christian Gillot, cgillot@neo-rousseaux.org


Page suivante   Page précédente   Table des matières