Aller au contenu

Introduction à la POO

Objets : attributs et création

Le libraire du coin de votre rue décide de faire appel à vous pour informatiser son système de gestion de livres : l'objectif de ce tp est de comprendre comment on peut rassember les informations se rapportant à un livre, ainsi que les opérations que l'on peut effectuer sur les livres (en calculer le prix, par exemple) dans une structure cohérente.

En python, le mot-clé class permet de définir un nouveau type : c'est une nouvelle structure de donnée qui permet de de représenter, structurer et manipuler des objets.

###

class Livre:bksl-nl passbksl-nlbksl-nllivre1 = Livre()bksl-nlbksl-nl

Attributs d'un objet

Le code ci-dessous permet d'ajouter différents attributs au livre : son titre (La peste), son auteur (Albert Camus), et son nombre total de page (59).

###

livre1.titre = "La peste"bksl-nllivre1.auteur = "Camus Albert"bksl-nllivre1.nbpy-undpages = 59bksl-nlbksl-nllivre2 = Livre()bksl-nl# À compléterbksl-nllivre2.titre = ...bksl-nllivre2.auteur = ...bksl-nllivre2.nbpy-undpages = ...bksl-nlbksl-nl

  1. Utiliser Thonny pour inspecter l'objet livre1 : dans le menu Affichage, faire afficher les panneaux Variables et Inspecteur d'objets en cliquant sur ces entrées. Une fois le panneau Inspecteur d'objets ouvert, cliquer sur le bouton Attributs. Commenter.

  2. Écrire le code python permettant de représenter le livre Fondation (256 pages), écrit par Isaac Asimov en 1951.

    1
    2
    3
    4
    5
    livre2 = Livre()
    # À compléter
    livre2.titre = ...
    livre2.auteur = ...
    livre2.nb_pages = ...
    

Création d'un nouveau livre

Écrire une fonction creer_livre qui prend en argument une chaine de caractère t, une chaîne de caractères a et un entier positif n et qui renvoie l'objet de type Livre de titre t, d'auteur a et constitué de n pages.

###

def creerpy-undlivre(t, a, n):bksl-nl """ str, str, int -> Livrebksl-nl Renvoie un nouveau livre """bksl-nl passbksl-nlbksl-nl

À l'aide de la fonction creer_livre, instancier une variable livre3 de type Livre qui représente le livre Liens de sang, écrit par Octavia Butler et publié pour la première fois en 1979 (467 pages dans l'édition française par la maison Au diable vauvert).

Fonction __init__

Commenter tout le code précédemment écrit. On remplace la définition précédente de la classe Livre par la définition suivante.

###

class Livre:bksl-nl def py-undpy-undinitpy-undpy-und(self, t, a, n):bksl-nl self.titre = tbksl-nl self.auteur = abksl-nl self.nbpy-undpages = nbksl-nlbksl-nl

  1. Exécuter ce code, puis exécuter l'instruction suivante dans la console :

    1
    Livre("Les misérables", "Hugo Victor", 2135)
    

    Observer l'effet sur l'état de la mémoire. Commenter.

  2. À quoi peut server la fonction __init__ placée dans le corps de la classe Livre ?

    1. Peut-on encore instancier une variable de type Livre avec l'instruction Livre() ?

    2. Écrire les instructions permettant d'instancier les variables livre1 (​La peste, Albert Camus, 59 pages), livre2 (​Fondation, Isaac Asimov, 256 pages), livre3 (​Liens de sang, Octavia Butler, 467 pages) et livre4 (​Les misérables, Victor Hugo, 2135 pages) avec cette nouvelle définition de la classe Livre.

Premières fonctions

Afficher un livre

Le libraire est un peu perturbé par l'effet de l'instruction print(livre1) : il préfèrerait un affichage plus lisible. La fonction affiche prend en argument un objet lvr de type Livre et réalise un affichage partiel des informations contenues dans l'objet lvr.

Modifier la fonction affiche afin que l'appel affiche(livre1) indique également le nom de l'auteur du livre dans la description affichée. Tester votre modification sur les variables de type Livre déjà définies.

###

def affiche(lvr):bksl-nl """ Livre -> Nonebksl-nl Affiche le livre lvr """bksl-nl titrepy-undlivre = lvr.titrebksl-nl pagespy-undtot = lvr.nbpy-undpagesbksl-nl # À modifierbksl-nl print(f"< Livre '{titrepy-undlivre}', nombre de pages {pagespy-undtot} >")bksl-nlbksl-nl

Prix d'un livre

Prix de base

Ce libraire peu adepte de la qualité intrinsèque des livres calcule le prix d'un livre de la manière suivante :

  • le prix du livre est égal à la somme des prix de ses pages ;
  • chaque page avant la 100è (inclue) coûte 10 centimes ;
  • chaque page entre la 101è (inclue) et la 1000è (inclue) coûte 2 centimes ;
  • chaque page après la 1001è (inclue) coûte 1 centime.

Écrire une fonction prix qui étant donné un objet lvr de type Livre renvoie le prix du livre lvr.

###
def testpy-undprix():bksl-nl """ Tests pour la fonction prix """bksl-nl livre1 = Livre("La peste", "Camus Albert", 59)bksl-nl assert prix(livre1, 0.12) == 7.08bksl-nl print("Tests de prix passés avec succès.")bksl-nl return Truebksl-nlbksl-nl# from tp import Livre, prixbksl-nl# testpy-undprix()bksl-nlbksl-nl 5/5

def prix(lvr):bksl-nl """ Livre -> floatbksl-nl Calcule le prix d'un livre """bksl-nlbksl-nl

Prix réduit

Il arrive au libraire de faire occasionnellement des réductions sur le prix des livres. Comme il oublie systématiquement quel calcul il doit effectuer sur sa calculatrice, il aimerait disposer d'une fonction toute prête qui fasse le travail à sa place.

Écrire une fonction prix_reduit qui étant donné un objet lvr de type Livre et un pourcentage de réduction reduc (un entier compris entre 0 et 100) calcule le prix du livre, après une réduction de reduc pourcent.

###
def testpy-undprixpy-undreduit():bksl-nl """ Tests pour la fonction prixpy-undreduit """bksl-nl livre1 = Livre("La peste", "Camus Albert", 59)bksl-nl assert prixpy-undreduit(livre1, 0.12, 50) == 3.54bksl-nl print("Tests de prixpy-undreduit passés avec succès.")bksl-nl return Truebksl-nlbksl-nl# from tp import prixpy-undreduitbksl-nl# testpy-undprixpy-undreduit()bksl-nlbksl-nl 5/5

def prixpy-undreduit(lvr, reduc):bksl-nl """ Livre, int -> floatbksl-nl Renvoie le prix du livre après réduction """bksl-nl passbksl-nlbksl-nl

Méthodes d'un objet

Sur ce même modèle, on peut imaginer :

  • d'autres attributs pour la classe Livre. Ils permettent d'ajouter des informations qui permettent de décrire l'objet.
  • d'autres fonctions (ou méthodes) opérant sur les objets de type Livre. Elles permettent de réaliser des opérations sur les objets de type Livre.

Afin de structurer efficacement notre code, nous allons encapsuler toutes ces informations dans la classe qui représente notre objet.

Commenter tout le code précédemment écrit, copier-coller le code suivant et exécuter le programme.

###
def testpy-undlibrairie():bksl-nl """ Tests pour la fonction librairie """bksl-nl print("Tests de librairie passés avec succès.")bksl-nl return Truebksl-nlbksl-nl# from tp import librairiebksl-nl# testpy-undlibrairie()bksl-nlbksl-nl 5/5

class Livre:bksl-nl def py-undpy-undinitpy-undpy-und(self, t, a, n):bksl-nl self.titre = tbksl-nl self.auteur = abksl-nl self.nbpy-undpages = nbksl-nlbksl-nl def affiche(self):bksl-nl """ Livre -> None """bksl-nl titrepy-undlivre = self.titrebksl-nl auteurpy-undlivre = self.auteurbksl-nl pagespy-undtot = self.nbpy-undpagesbksl-nl print(f"< Livre '{titrepy-undlivre}', auteur {auteurpy-undlivre}, nombre de pages {pagespy-undtot} >")bksl-nlbksl-nl def prix(self):bksl-nl """ Livre -> floatbksl-nl Calcule le prix d'un livre """bksl-nl if self.nbpy-undpages <= 100:bksl-nl return self.nbpy-undpages py-str 0.10bksl-nl elif 100 <= self.nbpy-undpages <= 1000:bksl-nl return 100py-str0.10 + (self.nbpy-undpages - 100)py-str0.01 bksl-nl else: bksl-nl return 100py-str0.10 + 900py-str0.02 + (self.nbpy-undpages - 1000)py-str0.01bksl-nlbksl-nl# Initialisation des variablesbksl-nllivre1 = Livre("La peste", "Camus Albert", 59)bksl-nllivre2 = Livre("Fondation", "Asimoov Isaac", 265)bksl-nllivre3 = Livre("Liens de sang", "Octavia Butler", 467)bksl-nllivre4 = Livre("Les misérables", "Victor Hugo", 2135)bksl-nlbksl-nl

Méthodes d'un objet : utilisation

Exécuter dans la console les lignes suivantes.

###

livre1.affiche()bksl-nllivre1.prix()bksl-nlbksl-nl

  1. Quelle est la différence entre cette syntaxe en notation objet et la syntaxe affiche(livre1) et prix(livre1) ?
  2. Copier-coller le code de la fonction prix_reduit dans la classe Livre, au même degré d'indentation que celui de la fonction prix.

    1. Exécuter dans la console l'instruction livre1.prix_reduit(50).

      Commenter et corriger l'erreur soulevée par python.

      À quoi ce résultat correspond-t-il ?

    2. Quelle instruction python permet de calculer le prix du roman Les misérables, si on lui applique une réduction de 42% ?

Ajout d'un attribut

Modifier la méthode __init__ de la classe Livre afin d'ajouter un attribut disponible à la classe Livre : il s'agit d'un entier positif ou nul qui représente combien de livres de ce type sont disponibles chez le libraire. L'attribut disponible d'un livre aura pour valeur par défaut 1.

Reception d'un livre

Écrire une méthode recevoir de la classe Livre : cette méthode prend comme argument un nombre entier n correspondant au nombre de copies supplémentaires reçues du livre self. Celles-ci seront ajoutées aux copies disponibles du livre : on modifiera pour cela l'attribut disponible.

Attention. On rappelle que le code de cette méthode devra être écrit dans la classe Livre (c'est à dire au bon niveau d'indentation).

1
2
3
4
def recevoir(self, n):
    """ Livre, int -> None
    n nouveaux exemplaires du livre sont disponibles """
    pass

Vente d'un livre

Écrire une méthode vendre de la classe Livre qui prend en argument un entier reduc et qui simule la vente du livre self :

  • si aucun livre de ce type n'est disponible, la méthode renvoie 0.
  • sinon : on calcule le prix du livre self en appliquant la réduction de reduc pourcent, et on décrémente de 1 l'attribut disponible de self.

    Enfin la méthode renvoie le prix du livre en euros, arrondi au centime.

1
2
3
def vendre(self, prix_page, réduc):
    """ Vend le livre, renvoie l'argent généré par la vente. """
    pass

Gestion d'une librairie

Introduction et motivation

Notre libraire cherche maintenant à gérer une collection de livres. Son stock de livres ne faisant qu'augmenter, il souhaite pouvoir répondre aux clients lui demandant s'il possède ou non un livre dont on lui donne le titre.

Écrire une fonction recherche qui étant donné une liste de livres collection et un titre, renvoie le nombre d'exemplaires disponibles du livre intitulé titre que possède le libraire. On supposera que chaque titre de la liste collection est unique.

###
def testpy-undrecherche():bksl-nl """ Tests pour la fonction recherche """bksl-nl collection = [bksl-nl Livre("Harry Potter et la Pierre Philosophale", "J.K. Rowling", 336),bksl-nl Livre("Le Seigneur des Anneaux", "J.R.R. Tolkien", 1216),bksl-nl Livre("1984", "George Orwell", 328),bksl-nl Livre("Le Petit Prince", "Antoine de Saint-Exupéry", 96),bksl-nl Livre("Don Quichotte", "Miguel de Cervantes", 928)bksl-nl ]bksl-nl dispos = [2, 0, 12, 42, 16]bksl-nl for l, n in zip(collection, dispos):bksl-nl l.disponible = nbksl-nl assert recherche(collection, "Harry Potter et la Pierre Philosophale") == 2bksl-nl assert recherche(collection, "Harry Potter") == 0bksl-nl assert recherche(collection, "Le Seigneur des Anneaux") == 0bksl-nl assert recherche(collection, "Don Quichotte") == 16bksl-nl print("Tests de recherche passés avec succès.")bksl-nl return Truebksl-nlbksl-nl# from tp import recherchebksl-nltestpy-undrecherche()bksl-nlbksl-nl 5/5

def recherche(collection, titre):bksl-nl """ [Livre], str -> intbksl-nl Nombre de livres disponible avec le titre indiqué dans la collection. """bksl-nl passbksl-nlbksl-nl

La classe Librairie

Afin de structurer efficacement notre code, on décide de regrouper toutes les fonctions opérant sur une collection de livres dans une classe intitulée Librairie. Ainsi, à l'aide de cette classe, le libraire pourra efficacement gérer l'ensemble des livres de sa librairie. Dans le code ci-dessous, l'attribut collection est un objet de type list constitué d'objets de type Livre.

###

class Librairie:bksl-nl def py-undpy-undinitpy-undpy-und(self, c):bksl-nl self.collection = cbksl-nlbksl-nl

  1. Avec quelle instruction instancie-t-on une librairie vide (ne contenant aucun livre) ?

  2. Instancier une variable lib de type Librairie représentant une librairie contenant les livres suivants :

    • 8 exemplaires du livre La peste, d'Albert Camus (59 pages) ;
    • 2 exemplaires du livre Fondation, d'Isaac Asimov (256 pages) ;
    • 4 exemplaires du livre Liens de sang, d'Octavia Butler (467 pages)
    • 3 exemplairs du livre Les misérables, de Victor Hugo (2135 pages) ;
    • 5 exemplaires du livre Harry Potter à l'école des sorciers, de J. K. Rowling (132 pages)
    1. Transformer la fonction recherche écrite précédemment en une méthode recherche de la classe Librairie.

    2. En utilisant la syntaxe de la notation objet, écrire l'instruction permettant de déterminer le nombre d'exemplaires du livre Liens de sang présents dans la collection du libraire.

Ajouter un livre dans une librairie

  1. Écrire une méthode ajoute de la classe Librairie qui prend en argument un objet lvr de type Livre et qui l'ajoute à la librairie représentée par self : vous modifierez pour cela l'attribut contenu de la variable self en lui ajoutant l'objet lvr.

    On supposera que l'objet l'objet lvr n'est pas déjà présent dans la liste self.contenu.

    1
    2
    3
    4
    def ajoute(self, lvr):
        """ Librairie, Livre -> None
        Ajoute le livre lvr à la librairie self """
        pass
    
  2. Écrire le code python permettant d'ajouter à la variable lib définie précédemment 11 exemplaires du livre Le roi Babar (15 pages), écrit par Jean de Brunhoff.

(difficile, à passer en première lecture) Modifier la méthode ajoute afin de prendre en compte le cas où des exemplaires du livre lvr seraient déjà présent dans la collection du libraire.

Afficher l'ensemble des livres de la librairie

Écrire une méthode affiche de la classe Librairie qui affiche les informations de tous les livres présents dans la librairie self.

On utilisera pour cela un parcours de liste de telle sorte que pour chaque élément lvr de l'attribut collection de la variable self, on fasse appel à la méthode affiche de l'objet de lvr afin d'afficher le livre en question.

1
2
3
4
def affiche(self):
    """ Librairie -> None
    Affiche les livres de la librairie  """
    pass

À vous de jouer

    1. Ajouter un nouvel attribut de votre choix à la classe Livre.

    2. Écrire une méthode de la classe Livre qui ajoute une fonctionnalité aux objets de type Livre (à vous de l'inventer !).

    1. Ajouter un nouvel attribut de votre choix à la classe Librairie.

    2. Écrire une méthode de la classe Librairie qui ajoute une fonctionnalité aux objets de type Librairie (à vous de l'inventer !).