Py: OOP 1 intro
Py: OOP 1 intro

Programmation orienté objet: introduction

Directory

serie

Sources

Recapitulatif

  • Un objet se crée en instanciant une classe
  • Une classe est un plan décrivant un objet et est composé de
    • méthodes (comportement)
    • attributs (données)
class Article:
    def __init__(self, titre):
        self.titre = titre

a1 = Article("J'aime la viande")
print(a1.titre)
  • Les méthodes nommées __methode__ (avec deux underscores) sont appelées automatiquement dans certaines conditions. __init__ est appelée automatiquement après la création de l’objet, et on s’en sert pour créer l’état de départ de l’objet (initialiser).

  • self est le premier paramètre qu’on passe à une méthode et représente l’objet en cours.

Base

La programmation orienté objet est un style (paradigme) de programmation qui permet de regrouper au même endroit le comportement (fonctions) et les données (structures) qui sont faites pour aller ensemble.

La POO a pour principal attrait de permettre de proposer une belle API, c’est à dire de créer du code réutilisable et facile à manipuler.

Il n’y a rien qu’on puisse faire en POO qu’on ne puisse faire autrement. On l’utilise principalement pour donner un style au code.

En réalité, on fait de la POO principalement pour faciliter la vie de ceux qui vont utiliser notre code plus tard.

Objet

Un objet est un moyen de dire à la machine : “Ce random nom possède telle donnée, et fait telle chose avec”.

En Python absolument tout est un objet.

Créer des objets se fait en deux étapes:

  • Décrire à quoi ressemble l’objet $ \Rightarrow $ classe
class DescriptionObjet:
    pass
  • Création de l’objet
>>> nouvel_objet = DescriptionObjet()
>>> print(nouvel_objet)
<__main__.DescriptionObjet object at 0x7f3d96b8a898>

La variable nouvel_objet contient un objet issu de la classe DescriptionObjet.

La variable nouvel_objet contient une instance de DescriptionObjet $ \Rightarrow $ L’action de créer un objet à partir d’une classe est appelée instanciation.

Python ne connait pour le moment que le nom et l’adresse en mémoire de l’objet et c’est ce qu’il affiche suite à un print().

On peut créer autant d’objets que l’on veut à partir d’une classe.

Méthodes

Fonctions déclarées à l’intérieur d’une classe.

class DescriptionObjet:
    def methode(objet_en_cours):
        print("poule")

Cette fonction méthode n’existe pas en dehors de la classe.

>>> methode()
  File "/home/sol/Code/Python/Tuto/Class/04SamEtMax/00.py", line 5, in <module>
    methode()
NameError: name 'methode' is not defined

Mais elle est attachée à chaque objet. On peut l’utiliser via la notation par point. Il nous faut donc automatiquement l’instance d’une classe pour appeler une méthode:

>>> nouvel_objet = DescriptionObjet()
>>> nouvel_objet.methode()
poule

Objet en cours (self)

Quand on appel une méthode depuis un objet, l’objet est passé en premier paramètre par Python. C’est automatique et invisible.

class DescriptionObjet:
    def methode(objet_en_cours):
        return objet_en_cours

nouvel_objet = DescriptionObjet()
print(nouvel_objet)
print(nouvel_objet.methode())

output:

<__main__.DescriptionObjet object at 0x7f48f271e940>
<__main__.DescriptionObjet object at 0x7f48f271e940>

nouvel_objet et objet_en_cours contiennent la même chose : l’objet en cours. objet_en_cours est le nom que nous avons donné à notre premier argument, mais Python passe toujours automatiquement en premier argument l’objet en cours afin que nous puissions modifier cet objet à l’intérieur d’une méthode.

Paramètre objet_en_cours $ \Rightarrow $ instance courante

Une méthode doit toujours déclarer au moins un paramètre pour accueillir la référence à l’objet en cours !

Conventions

  • On nomme les classes en CamelCase
  • On nomme le reste en minuscules avec des underscores:
    • nom_de_methode
    • nom_d_attribut
  • Le premier paramètre (objet_en_cours) se nome self
  • Les méthodes appelées automatiquement sont appelées __nom_de_methode__ (avec deux underscores)

Attributs

Tout comme les méthodes sont des fonctions attachées à un objet, les attributs sont des variables attachées à un objet.

En réalité les méthodes sont aussi des attributs

Python est un langage dynamique et permet d’ajouter n’importe quel attribut à n’importe quel objet via la notation par point:

>>> nouvel_objet.attribut
Traceback (most recent call last):
  File "/home/sol/Code/Python/Tuto/Class/04SamEtMax/00.py", line 9, in <module>
    print(nouvel_objet.attribut)
AttributeError: 'DescriptionObjet' object has no attribute 'attribut'
>>> nouvel_objet.nouvel_attribut = "poule"
>>> print(nouvel_objet.nouvel_attribut)
poule

Intéret de self:

class DescriptionObjet:
    def afficher(self):
        print(self.attribut)
    
    def modifier(self):
        self.attribut = "autre valeur"

On peut accéder aux attributs depuis l’intérieur et l’extérieur d’un objet:

>>> un_objet = DescriptionObjet()
>>> un_objet.afficher()

Comme l’attribut n’existe pas encore Python renvoie:

Traceback (most recent call last):
  File "/home/sol/Code/Python/Tuto/Class/04SamEtMax/00.py", line 9, in <module>
    un_objet.afficher()
  File "/home/sol/Code/Python/Tuto/Class/04SamEtMax/00.py", line 3, in afficher
    print(self.attribut)
AttributeError: 'DescriptionObjet' object has no attribute 'attribut'
>>> un_objet.attribut = "maintenant il existe !"
>>> un_objet.afficher()
maintenant il existe !
>>> un_objet.modifier()
>>> un_objet.attribut
'autre valeur'

Une méthode peut modifier l’objet en cours en fonction des paramètres passés:

class DescriptionObjet:
    def afficher(self):
        print("valeur actuelle:", self.attribut)
    
    def modifier(self, valeur):
        self.attribut = valeur * 2

>>> un_objet = DescriptionObjet()
>>> un_objet.attribut = 1
>>> un_objet.afficher()
valeur actuelle: 1
>>> un_objet.modifier(2)
>>> un_objet.afficher()
valeur actuelle: 4

Les méthodes servent à retourner les valeurs à l’intérieur de l’objet, ou à les modifier.

Initialisation d’un objet

On utilise une méthode appelée automatiquement (__methode__) après la création de l’objet pour initialiser des attributs sans devoir les créer à chaque fois. Cette méthode est __init__.

class DescriptionObjet:
    def __init__(self):
        print("L'objet a ete cree !")
        print("Cette methode est appelee automatiquement")

un_objet = DescriptionObjet()

output:

L'objet a ete cree !
Cette methode est appelee automatiquement

__init__ est une méthode tout à fait ordinaire. Seul le nom est important car il est detecté par Python qui l’appelle au bon moment.

C’est principalement utile pour fournir un état de départ:

class Voiture:
    def __init__(self):
        self.carburent = 100
        self.couleur   = "noire"

v = Voiture()
print(v.couleur)
print(v.carburent)

output:

noire
100

Si on passe des paramètres à l’instanciation, ils sont passés automatiquement à __init__ qui comme toutes les fonctions méthodes peut avoir des paramètres par défaut.

class Voiture:
    def __init__(self, cb_de_carburent=100, quelle_couleur="noire"):
        self.carburent = cb_de_carburent
        self.couleur   = quelle_couleur

v1 = Voiture()
print("\nv1:")
print(v1.couleur)
print(v1.carburent)

v2 = Voiture(50, 'rouge') 
print("\nv2:")
print(v2.couleur)
print(v2.carburent)

v3 = Voiture(quelle_couleur="gris")
print("\nv3:")
print(v3.couleur)
print(v3.carburent)

v4 = Voiture(12)
print("\nv4:")
print(v4.couleur)
print(v4.carburent)

output:

v1:
noire
100

v2:
rouge
50

v3:
gris
100

v4:
noire
12

Par convention les noms de paramètres sont les mêmes que ceux des attributs:

class Voiture:
    def __init__(self, carburent=100, couleur="noire"):
        self.carburent = carburent
        self.couleur   = couleur

Self

Pour mieux comprendre self nous allons utiliser la fonction id() qui retourne l’adresse en mémoire de l’objet passé en argument.

id() retourne un int, hex() nous permet de l’avoir sous format hexadecimal

La méthode print_self() de la classe suivante nous permet d’identidier self:

class Article:
    def __init__(self, titre):
        self.titre = titre
    
    def print_self(self):
        print(self.titre)
        print(self)
        print(hex(id(self)))

article = Article("Poules et cochons")

Affichage du titre et des adresses de l’article:

>>> print(article.titre)
Poules et cochons
>>> print(article)
<__main__.Article object at 0x7f502be38c88>
>>> print(hex(id(article)))
0x7f502be38c88

Utilisation de la méthode self_print():

>>> articl1.print_self()
Poules et cochons
<__main__.Article object at 0x7f502be38c88>
0x7f502be38c88

Nous constatons que c’est exactement la même chose. self est article. C’est ça que veut dire être l’objet en cours.

Suite