Programmation Orientée Objet

La programmation orientée objet (POO) est un paradigme de programmation informatique. Il consiste en la définition et l’interaction de briques logicielles appelées objets ; un objet représente un concept, une idée ou toute entité du monde physique,.

exemples : une voiture, une personne, une page d’un livre…

L’objet possède en interne une structure et un comportement, et il sait interagir avec ses pairs.

Il s’agit donc de représenter ces objets et leurs relations ; l’interaction entre les objets via leurs relations permet de concevoir et réaliser les fonctionnalités attendues, de mieux résoudre des problèmes. Dès lors, l’étape de modélisation revêt une importance majeure et nécessaire pour la POO. C’est elle qui permet de transcrire les éléments du réel sous forme virtuelle.

source : Wikipédia

1967 : premier langage orienté objet : Simula 67

La programmation orientée objet a fait son apparition dans le langage Simula 67 puis SmallTalk. Puis elle s’est développée dans les langages anciens comme le Fortran, le Cobol et est même incontournable dans des langages récents comme Java.

 

Cette façon d’aborder la programmation possède plusieurs avantages :

  • les différents objets peuvent être construits indépendamment les uns des autres (par exemple par des programmeurs différents)
    Ce qui permet de :

    • éviter tout risque d’interférence,
    • éviter au maximum l’emploi de variables globales.
  • la classification des objets en familles permet de construire de nouveaux objets à partir d’objets préexistants
    Ce qui permet de :

    • réutiliser des pans entiers d’une programmation déjà écrite, pour en tirer une fonctionnalité nouvelle.
      Cela est rendu possible grâce aux concepts de polymorphisme et  d’héritage (pas au programme de NSI).

 

L’objet et la classe

Un objet est un élément d’une classe (en quelque sorte un « type personnalisé » ; il faut entendre type au même titre qu’un nombre, une chaîne de caractères, …).

Définir une classe revient à définir une nouvelle structure de données, qui s’ajoute à celles définies par le langage.

Classe = Type d’objet

Objet = Instance de Classe

Définition de classe

Avant de créer un objet, il faut avoir défini sa classe.

Une classe possède un nom et des membres, c’est à dire des attributs (ou champs) et des méthodes.

Chaque membre d’un objet objet est accessible via l’expression : objet.membre.

  • Les attributs (ou champs) : ils sont à l’objet ce que les variables sont à un programme.

les attributs sont donc typés (exemple int, float, bool, str, … ou n’importe quelle autre classe !)

  • Les méthodes sont des procédures ou fonctions destinées à traiter les données. Elles servent d’interface entre les données et le programme.

les méthodes acceptent donc des arguments et peuvent renvoyer des valeurs

Le fait de réunir dans un même objet les attributs et les méthodes se nomme l’encapsulation. Cela permet de cacher à l’utilisateur d’un objet certaines données ou procédures internes.

En Python, tout est objet !!
Par exemple le module  math est un objet, et possède donc :

  • des attributs : pi, …
  • des méthodes : cos(), …

Encapsulation : Objet = Attributs + Méthodes

En Python, on définit une classe grâce à l’instruction class  :

class NomDeLaClasse:    
    <bloc de définition de la classe>

Remarque : par convention, les classes doivent être nommées en CamelCase : une suite de mots, sans espace ni séparateur, dont la première lettre est une capitale.

 

Le bloc de définition d’une classe contient :

  • des attributs de classe (voir plus bas …)
  • des méthodes :
    • des méthodes spéciales : leurs noms, réservés par le langage Python, commencent et finissent par « __ » : deux tirets « bas »
    • des méthodes personnalisées
    • des méthodes privées (inaccessibles en dehors des méthodes de l’objet lui-même) : leurs noms commencent par « __ » : deux tirets « bas »

 

Instanciation d’objet

Une fois la classe définie, on peut créer autant d’objets de cette classe (on parle d’instances) que l’on veut :

mon_1er_objet = NomDeLaClasse() 
mon_2eme_objet = NomDeLaClasse() 
...

 

L’opération qui permet de créer l’objet s’appelle la construction.

À chaque construction d’un objet, la méthode __init__()  de la classe est exécutée.

Cette méthode permet en générale de définir les différents attributs de l’objet :

class NomDeLaClasse:
   def __init__(self, attr1, attr2 = 0): 
      self.attribut1 = attr1 
      self.attribut2 = attr2

 

… et la construction de l’objet permet de leur attribuer des valeurs :

mon_1er_objet = NomDeLaClasse("Salut") 
print(mon_1er_objet.attribut1) # affiche 'Salut' 
print(mon_1er_objet.attribut2) # affiche 0, sa valeur par défaut

 

Attributs d’instance / Attributs de classe

Chaque objet peut contenir ses propres valeurs d’attributs, ce  sont les attributs d’instance.

Mais on peut également attribuer des attributs à la classe elle-même, de sorte que tous les objets de cette classe puissent les utiliser. On parle d’attributAttribut Un attribut est un identifiant (un nom) décrivant une information stockée dans une base. Les attributs correspondent aux colonnes si la relation à laquelle il appartient est représentée sous forme de table. de classe (static en Java ou en C++), et en Python, on les définit au niveau du bloc de définition de la classe :

class NomDeLaClasse: 
   attribut_0 = 100 # attribut de classe    
   def __init__(self, attr1, attr2 = 0): 
      self.attribut1 = attr1 # attribut d'instance 
      self.attribut2 = attr2 + NomDeLaClasse.attribut_0

Accès à  un attribut de la classe NomDeLaClasse:

print(NomDeLaClasse.attribut_0) # affiche 100

 

Accès aux attributs de différentes instances de la classe NomDeLaClasse:

mon_1er_objet = NomDeLaClasse("Bonjour")
print(mon_1er_objet.attribut1)    # affiche 'Bonjour'
print(mon_1er_objet.attribut2)    # affiche 100

 

 


Un peu de géométrie …

Le point

Soit \(M\) un point du plan \(\left(\vec{x}, \vec{y}\right)\) et de coordonnées cartésiennes \(x_M\) et \(y_M\) dans un repère \(\mathrm{R}\left(O, \vec{x}, \vec{y}\right)\).

On peut considérer le point comme un objet géométrique, possédant 2 attributs : ses coordonnées dans \(\mathrm{R}\).

 

Définition de classe en Python :

class Point: 
    def __init__(self, x, y, z): # méthode "constructeur" 
        self.x = x # 
        self.y = y # attributs: coordonnées

Remarque : le paramètre selfdésigne l’objet lui même. On utilise ce terme à l’intérieur de la classe (arguments et méthodes) pour éviter les ambiguïtés lorsque l’on s’intéresse aux membres de l’objet (self.x= « c’est mon x »).

>>> M = Point(1, 3, -2) 
>>> M 
<__main__.Point object at 0x004D4910>

Si on souhaite afficher des informations plus explicites sur le point, on peut déclarer, à l’intérieur de la déclaration de classe, la méthode __repr__()(il s’agit d’un nom réservé, d’où les deux caractères « _ ») :

def __repr__(self): # méthode pour l'affichage 
    return "P(%.4f, %.4f, %.4f)" %(self.x, self.y, self.z)

Cette méthode n’attend aucun autre argument que l’objet lui même (self) et doit renvoyer une chaîne de caractères.

Ce qui aura pour conséquence le comportement suivant :

>>> M 
P(1, 3, -2)

Remarque : toutes les méthodes ou attributs commençant par « __ » (deux tirets-bas) sont privés, c’est à dire qu’ils ne peuvent être utilisés que depuis l’intérieur même de l’objet.

On peut créer ses propres membres privés (en plus des noms déjà réservés) pour mieux contrôler la modification des données de l’objet.

 Écrire une fonction distance(P1, P2) admettant 2 objets de type Point comme paramètres et renvoyant la valeur de la distance entre ces deux points.

Rappel : la distance entre deux points \(A\begin{pmatrix}x_A \\ y_A \\\end{pmatrix}\) et \(B\begin{pmatrix}x_B \\ y_B \\\end{pmatrix}\) s’exprime
\(D=\sqrt{\left(x_B-x_A\right)^2+\left(y_B-y_A\right)^2}\)

 

Pour afficher ce point graphiquement on peut utiliser le module pylab :

import pylab

# tracé d'un simple point :
pylab.plot(x, y)

# pour placer toute la figure dans un repère orthonormé :
pylab.axis('scaled')
# affichage de la figure :
pylab.show()
Rajouter à la classe Point une méthode dessiner permettant d’afficher graphiquement les instances de Point dans un espace orthonormé.

Ainsi, si on exécute les commandes suivantes :

p1 = Point(4, 4)
p1.dessiner()

p2 = Point(2, 5)
p2.dessiner()

p3 = Point(-1, 2)
p3.dessiner()

On doit voir apparaitre :

 

La fonction pylab.plot accepte également un 3ème argument facultatif permettant de spécifier la couleur du tracé. Cette information peut être donnée sous la forme d’un simple caractère, parmi ‘b’, ‘g’, ‘r’, ‘c’, ‘m’, ‘y’, ‘k’, ‘w’.

 

Rajouter à la fonction de construction des instances de Point un paramètre facultatif c, de valeur par défaut égale au caractère "k" .

Ainsi, si on exécute les commandes suivantes :

p1 = Point(4, 4, 'r')
p1.dessiner()

p2 = Point(2, 5, 'y')
p2.dessiner()

p3 = Point(-1, 2, 'c')
p3.dessiner()

On doit voir apparaitre :

 

 

 

Le vecteur

De même que pour le point, on peut définir un vecteur par ses 2 coordonnées dans le repère \(\mathrm{R}\).

Définition de classe en Python :

class Vecteur: 
   def __init__(self, x, y, z): # méthode "constructeur" 
      self.x = x # 
      self.y = y # attributs : coordonnées 

Et pour en tracer un représentant dans le plan, on utilise la fonction pylab.quiver:

pylab.quiver(x0, y0, x, y, units='xy' ,scale=1)

 

Implémenter une méthode dessiner, admettant un seul paramètre p (en plus de l’objet lui même bien sûr) de type Point et permettant d’afficher un représentant de ce vecteur au point p.

Ainsi, si on rajoute les commandes suivantes aux précédentes :

v1 = Vecteur(1,2)
v1.dessiner(p3)

v2 = Vecteur(-3,-1)
v2.dessiner(p1)
v2.dessiner(p2)

On doit voir apparaitre :

 

 

 

Parmi les noms de méthodes spéciales (elles sont toutes ), il en existe une permettant d’utiliser le symbole « + » pour faire une « somme » de deux objets, de même type ou pas : la méthode __add__().

 

Écrire la méthode __add__ , acceptant comme argument (en plus du vecteur lui-même, self) un autre vecteur v , et en renvoyant le vecteur somme.

Le résultat doit permettre de faire ça (après avoir implémenté une méthode __repr__()comme pour le point) :

>>> u = Vecteur(1, 5)
>>> v = Vecteur(1, 4) 
>>> u + v 
v(2, 9)

 

Faire de même avec les opérateurs suivants :
nom de la méthode expression Python écriture mathématique
différence : __sub__ : u - v \(\vec{u}-\vec{v}\)
norme : __abs__ : abs(u) \(\|\vec{u}\|\)
négation : __neg__ : -u \(-\vec{u}\)
produit par un scalaire : __mul__ : k*u \(\vec{u}\times k\)
(dans ce dernier cas, les arguments étant de types différents, il faut aussi définir la fonction « réfléchie » __rmul__ , pour pouvoir faire k*u et u*k )
Adapter la méthode __mul pour qu’elle puisse également réaliser un produit scalaire.

 

Droite

Il existe plusieurs manières de définir une droite : Point+Vecteur, deux Points, deux Plans, un Point + un Plan…

Créer une classe Droite , dont le constructeur peut admettre différents types d’arguments (pourvu que ceux-ci puissent permettre la définition univoque de l’objet).

Pour tester si un objet est une instance d’une classe donnée, on peut utiliser la fonction isinstance(objet, NomDeLaClasse), qui renvoie alors Trueou False.

 

Pour passer à une fonction des arguments de nombre ou de type non prédéterminés, on peut utiliser l’opérateur « * » :

  • l’argument *args dans la définition de la fonction va récupérer tous les arguments donnés lors de l’appel de la fonction dans un tuple nommé args .

exemple : def mafct(*args)→ mafct("a", 2)→ args = ("a", 2)

  • l’argument **kargs dans la définition de la fonction va récupérer tous les arguments donnés lors de l’appel de la fonction dans un dictionnaire nommé kargs .

exemple : def mafct(**kargs)→ mafct(k="z", p=3)→ kargs = {'k': "z", 'p': 3}

  • et on peut combiner les deux :

exemple : def mafct(*args, **kargs)→ mafct("a", p="3")→ args = ("a",)et kargs = {p : "3"}

 

Améliorer la fonction distance() pour qu’elle admette également un Point et une Droite comme arguments, et en calcule la distance relative !

 

Sources :

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *