Copyright © 2000 Micheal Orr
Copyright © 2000 Christian Gillot
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
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.
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).
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 self
s 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.
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).
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.
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.
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.