Introduction à la programmation orientée objet en Python

Gazette Linux n°56 — Août 2000

Christian Gillot

Adaptation française 

Frédéric Marchal

Correction du DocBook 

Article paru dans le n°56 de la Gazette Linux d'août 2000.

Cet article est publié selon les termes de la Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.


Table des matières

Des maisons, encore des maisons !
Ne soyez pas si carré !
Déclaration de fonctions en dehors de la déclaration de la classe
Public ou privé ?
Les constructeurs de classe
Les tableaux et les classes

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 commenterai 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.

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).

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.

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).

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.

Les constructeurs de classe

La méthode __init__ est le constructeur.

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.

Adaptation française de la Gazette Linux

L'adaptation française de ce document a été réalisée dans le cadre du Projet de traduction de la Gazette Linux.

Vous pourrez lire d'autres articles traduits et en apprendre plus sur ce projet en visitant notre site : http://www.traduc.org/Gazette_Linux.

Si vous souhaitez apporter votre contribution, n'hésitez pas à nous rejoindre, nous serons heureux de vous accueillir.