Notion de classe

La programmation orientée objet (POO) est une technique de programmation indispensable pour des projets importants. La POO n'est pas au programme en ISN. Toutefois, lors de vos recherches sur le web, vous tomberez inévitablement sur des programmes écrits avec cette technique. Les pages consacrées à ce thème ont pour objectif de vous permettre de comprendre plus aisément de tels codes.

Par ailleurs, chaque année, des élèves décident d'utiliser la POO pour leur projet final : l'un des intérêts de la POO est de faciliter le travail à plusieurs sur un même programme, ce qui est justement l'une des contraintes du projet final en ISN.

Un point du plan en POO

Nous présentons ici un exemple utilisé fréquemment pour présenter la POO : définir un point et ses caractéristiques.

Cet exemple se prête en effet très bien à l'explication des principes. Qu'est-ce qu'un point ? C'est un objet. Ce point a des 'attributs' : une abscisse, une ordonnée dans un repère donné. On pourrait ajouter également d'autres attributs attachés à la représentation de ce point : sa forme (un petit rond, ou un petit carré ou une croix), sa couleur... Ces derniers attributs nous éloignent de l'objet mathématique mais c'est ici d'objet informatique dont nous allons parler.

Un peu de code vaut ici tous les discours :


class Point:
	""" Représente un point du plan. Chaque point a un nom 
	(qui sera défini par une chaîne de caractères), 
	une abscisse et une ordonnée (qui seront définis par des nombres)."""
	
	def __init__(self,  nom_du_point , x=0, y=0):
		""" initialise l'objet point avec une abscisse 
		et une ordonnée, par défaut toutes deux à 0. """
		self.nom = nom_du_point
		self.abscisse = x
		self.ordonnee = y
		
	def deplace(self, x, y):
		""" modifie l'emplacement du point en lui donnant une nouvelle abscisse
		et une nouvelle ordonnée."""		
		self.abscisse = x
		self.ordonnee = y

	def translate(self, dx, dy):
		""" translate le point par le vecteur de coordonnées (dx, dy)."""
		self.abscisse += dx
		self.ordonnee += dy
		
	def __str__(self) :
		""" méthode appelée lorsqu'on demandera un print de l'objet."""
		chaine1 = "Attributs du point {} :\n".format(self.nom) 
		chaine2 = "abscisse = {}, ordonnée = {}.\n"\
		.format(self.abscisse,self.ordonnee) 
		return chaine1+chaine2
		
		
if __name__ == '__main__' :		
		
 	# création de deux objets de type Point :
	a = Point('A')
	b  = Point('B',3, 5)
	print(a)
	print(b)
	
	# création d'un autre objet de type Point :
	c = Point('C', 2,2)
	print("Le point C avant translation : ")
	print(c)
	# translation du point c :
	c.translate(3,7)
	print("Le point C après translation : ")
	print(c)

Testez ce code. On obtient :

Attributs du point A :
abscisse = 0, ordonnée = 0.

Attributs du point B :
abscisse = 3, ordonnée = 5.

Le point C avant translation : 
Attributs du point C :
abscisse = 2, ordonnée = 2.

Le point C après translation : 
Attributs du point C :
abscisse = 5, ordonnée = 9.

Vous constatez par cet exemple que définir une classe, c'est avant tout définir un nouveau type en python. Après cette définition, à côté des listes, des chaînes... on dispose également de la possibilité de travailler avec des points.

Dans le code ci-dessus, le mot "self" est employé à plusieurs reprises. Il s'agit de faire référence à l'objet que l'on est en train de définir.
En fait, on pourrait utiliser un autre mot que 'self' mais l'usage est bien établi et il vaut mieux le respecter. Vous pouvez vérifier que le code ci-dessous fonctionne correctement également :


class Point:
	
	def __init__(objetencoursdedefinition,  nom_du_point , x=0, y=0):
		""" initialise l'objet point avec une abscisse 
		et une ordonnée, par défaut toutes deux à 0. """
		objetencoursdedefinition.nom = nom_du_point
		objetencoursdedefinition.abscisse = x
		objetencoursdedefinition.ordonnee = y
		
	def deplace(objetencoursdedefinition, x, y):
		""" modifie l'emplacement du point en lui donnant une nouvelle abscisse
		et une nouvelle ordonnée."""		
		objetencoursdedefinition.abscisse = x
		objetencoursdedefinition.ordonnee = y

	def translate(objetencoursdedefinition, dx, dy):
		""" translate le point par le vecteur de coordonnées (dx, dy)."""
		objetencoursdedefinition.abscisse += dx
		objetencoursdedefinition.ordonnee += dy
		
	def __str__(objetencoursdedefinition) :
		""" méthode appelée lorsqu'on demandera un print de l'objet."""
		chaine1 = "Attributs du point {} :\n".format(objetencoursdedefinition.nom) 
		chaine2 = "abscisse = {}, ordonnée = {}.\n"\
		.format(objetencoursdedefinition.abscisse,objetencoursdedefinition.ordonnee) 
		return chaine1+chaine2
		
		
if __name__ == '__main__' :		
		
 	# création de deux objets de type Point :
	a = Point('A')
	b  = Point('B',3, 5)
	print(a)
	print(b)
	
	# création d'un autre objet de type Point :
	c = Point('C', 2,2)
	print("Le point C avant translation : ")
	print(c)
	# translation du point c :
	c.translate(3,7)
	print("Le point C après translation : ")
	print(c)

On utilisera le vocabulaire suivant :

  1. Les caractéristiques de l'objet (définies dans __init__) seront nommées attributs de l'objet (dans notre exemple : le nom, l'abscisse et l'ordonnée du point).
  2. Les fonctions définies dans la classe seront appelées les méthodes de l'objet (dans notre exemple, les fonctions deplace, translate, __str__).

Syntaxe

self

Ci-dessus, nous avons vu que self pouvait être remplacé par un autre mot. Par contre, la présence d'un mot (et on choisira le mot self systématiquement) est indispensable. Toutefois l'usage peut paraître étrange : un paramètre est présent dans la définition mais ne semble pas présent dans l'appel.

Par exemple, on définit def translate(self, dx, dy) , mais lors de l'appel on a écrit c.translate(3,7) en ne faisant figurer que les paramètres dx et dy. Où est donc passé le paramètre de tête ? Eh bien en tête justement ! Ce paramètre est en fait la variable c placée devant dans c.translate(3,7). Il faut comprendre et s'habituer dans ce cadre à la position particulière de ce paramètre (qui est en fait, il est vrai, un peu plus qu'un simple paramètre).

__init__

La méthode __init__ a pour rôle d'initialiser l'objet. Elle définit ce que seront les attributs de l'objet ainsi que leurs valeurs initiales.

La syntaxe doit cette fois être impérativement respectée pour le nom de cette méthode.

__str__

Nous avons illustré le rôle de la méthode __str__ dans le code ci-dessus. La syntaxe est là aussi à respecter.

Vous pouvez maintenant traiter les premiers exercices.