Geekflare est soutenu par son public. Nous pouvons percevoir des commissions d'affiliation sur les liens d'achat présents sur ce site.
En Développement Dernière mise à jour : 25 septembre 2023
Partager sur :
Freshdesk - Le logiciel de support client facile à utiliser qui vous aide à offrir des expériences client agréables.

Dans cet article, vous allez construire une application de tables de multiplication, en utilisant la puissance de la programmation orientée objet (POO) en Python

Vous allez pratiquer les principaux concepts de la POO, et comment les utiliser dans une application entièrement fonctionnelle

Python est un langage de programmation multiparadigme, ce qui signifie qu’en tant que développeurs, nous pouvons choisir la meilleure option pour chaque situation et chaque problème. Lorsque nous parlons de programmation orientée objet, nous faisons référence à l’un des paradigmes les plus utilisés pour construire des applications évolutives, au cours des dernières décennies

Les bases de la POO

Nous allons jeter un coup d’œil rapide au concept le plus important de la P.O.O. en Python, les classes

Une classe est un modèle dans lequel nous définissons la structure et le comportement des objets. Ce modèle nous permet de créer des instances, qui ne sont rien d’autre que des objets individuels fabriqués suivant la composition de la classe

Une classe de livre simple, avec les attributs de titre et de couleur, serait définie comme suit

class Book :
 def __init__(self, title, color) :
 self.title = title
 self.color = color

Si nous voulons créer des instances de la classe book, nous devons appeler la classe et lui passer des arguments

# Objets d'instance de la classe Book
blue_book = Book("The blue kid", "Blue")
green_book = Book("The frog story", "Green")

Une bonne représentation de notre programme actuel serait la suivante

Class.png

Ce qui est génial, c’est que lorsque nous vérifions le type des instances blue_book et green_book , nous obtenons “Book”

# Impression du type des livres

print(type(blue_book))

#

<classe '__main__.Book'>
print(type(green_book))

#

<classe '__main__.Book'&gt

Après avoir clarifié ces concepts, nous pouvons commencer à construire le projet 😃

Déclaration de projet

En tant que développeurs/programmeurs, la plupart du temps n’est pas consacré à l’écriture de code, selon thenewstack nous ne passons qu’un tiers de notre temps à écrire ou à refactoriser du code

Nous passons les deux autres tiers à lire le code des autres et à analyser le problème sur lequel nous travaillons

Ainsi, pour ce projet, je vais générer un énoncé de problème et nous allons analyser comment créer notre application à partir de cet énoncé. Ainsi, nous réalisons le processus complet, depuis la réflexion sur la solution jusqu’à sa mise en œuvre avec du code

Un enseignant du primaire veut un jeu pour tester les compétences en multiplication des élèves de 8 à 10 ans.

Le jeu doit avoir un système de vies et de points, où l’élève commence avec 3 vies et doit atteindre un certain nombre de points pour gagner. Le programme doit afficher un message “perdant” si l’élève épuise toutes ses vies.

Le jeu doit avoir deux modes, les multiplications aléatoires et les multiplications en tableau.

Le premier doit donner à l’élève une multiplication aléatoire de 1 à 10, et il doit répondre correctement pour gagner un point. Si ce n’est pas le cas, l’élève perd un point et le jeu continue. L’élève ne gagne que lorsqu’il atteint 5 points.

Le deuxième mode doit afficher une table de multiplication de 1 à 10, où l’élève doit saisir le résultat de la multiplication en question. Si l’élève échoue trois fois, il perd, mais s’il réussit deux tables, le jeu se termine

Je sais que les exigences sont peut-être un peu plus grandes, mais je vous promets que nous les résoudrons dans cet article 😁

Diviser pour mieux régner

La compétence la plus importante en programmation est la résolution de problèmes. En effet, vous devez avoir un plan avant de commencer à pirater le code

Je suggère toujours de prendre le plus gros problème et de le diviser en plus petits qui peuvent être à la fois faciles et efficaces à résoudre

Ainsi, si vous devez créer un jeu, commencez par le diviser en ses parties les plus importantes. Ces sous-problèmes seront beaucoup plus faciles à résoudre

Ce n’est qu’à ce moment-là que vous saurez clairement comment exécuter et intégrer le tout dans le code

Réalisons donc un graphique de l’aspect du jeu

divide and conquer.png

Ce graphique établit les relations entre les objets de notre application. Comme vous pouvez le voir, les deux objets principaux sont la multiplication aléatoire et la multiplication par tableau. La seule chose qu’ils partagent, ce sont les attributs Points et Vies

Ayant toutes ces informations en tête, entrons dans le code

Création de la classe de jeu Parent

Lorsque nous travaillons avec la programmation orientée objet, nous cherchons le moyen le plus propre d’éviter la répétition du code. C’est ce qu’on appelle le DRY (don’t repeat yourself)

Note : Cet objectif n’est pas lié à l’écriture du moins de lignes de code possible (la qualité du code ne doit pas être mesurée par cet aspect) mais à l’abstraction de la logique la plus utilisée

Selon l’idée précédente, la classe mère de notre application doit établir la structure et le comportement désiré des deux autres classes

Voyons comment cela peut se faire

class BaseGame :

 # Longueur à laquelle le message est centré
 message_lenght = 60
    
 description = ""
        
 def __init__(self, points_to_win, n_lives=3) :
 """Classe de jeu de base

 Args :
 points_to_win (int) : les points dont le jeu aura besoin pour être terminé
 n_lives (int) : Le nombre de vies dont dispose l'élève. La valeur par défaut est 3.
 """
 self.points_to_win = points_to_win

 self.points = 0
        
 self.lives = n_lives

 def get_numeric_input(self, message="") :

 while True :
 # Obtenir l'entrée de l'utilisateur
 user_input = input(message)
            
 # Si l'entrée est numérique, la retourner
 # Si elle ne l'est pas, imprimer un message et répéter
 if user_input.isnumeric() :
 return int(user_input)
 else :
 print("L'entrée doit être un nombre")
 continue
             
 def print_welcome_message(self) :
 print("PYTHON MULTIPLICATION GAME".center(self.message_lenght))

 def print_lose_message(self) :
 print("DÉSOLÉ VOUS AVEZ PERDU TOUTES VIVRES".center(self.message_lenght))

 def print_win_message(self) :
 print(f "FÉLICITATIONS VOUS AVEZ ATTEINT {self.points}".center(self.message_lenght))
        
 def print_current_lives(self) :
 print(f "Actuellement vous avez {self.vies} vies")

 def print_current_score(self) :
 print(f"\NVotre score est de {self.points}")

 def print_description(self) :
 print("\N" self.description.center(self.message_lenght) "\N")

 # Méthode d'exécution de base
 def run(self) :
 self.print_welcome_message()
        
 self.print_description()

Wow, cela semble être une classe assez énorme. Laissez-moi l’expliquer en profondeur

Tout d’abord, il faut comprendre les attributs de la classe et le constructeur

Base-game-constructor.png

Fondamentalement, les attributs de classe sont des variables créées à l’intérieur de la classe, mais en dehors du constructeur ou de toute autre méthode

Les attributs d’instance, quant à eux, sont des variables créées uniquement dans le constructeur

La principale différence entre ces deux types d’attributs est leur portée, c’est-à-dire que les attributs de classe sont accessibles à la fois à partir d’un objet d’instance et de la classe. En revanche, les attributs d’instance ne sont accessibles qu’à partir d’un objet d’instance

game = BaseGame(5)

#

Accès à l'attr de classe longueur du message du jeu depuis la classe
print(game.message_lenght) # 60

#

Accès à l'attr de classe longueur du message depuis la classe
print(BaseGame.message_lenght) # 60

#

Accès à l'attr d'instance points depuis l'instance
print(game.points) # 0

#

Accès à l'attribut d'instance points depuis la classe
print(BaseGame.points) # Erreur d'attrib

ut


Un autre article peut approfondir ce sujet. Restez en contact pour le lire

La fonctionget_numeric_input est utilisée pour empêcher l’utilisateur de fournir des données qui ne sont pas numériques. Comme vous pouvez le remarquer, cette méthode est conçue pour interroger l’utilisateur jusqu’à ce qu’elle obtienne une entrée numérique. Nous l’utiliserons plus tard dans les classes d’enfants

Base-game-input.png

Les méthodes print nous permettent d’éviter d’imprimer la même chose à chaque fois qu’un événement se produit dans le jeu

Enfin, la méthode run n’est qu’une enveloppe que les classes Random multiplication et Table multiplication utiliseront pour interagir avec l’utilisateur et rendre le tout fonctionnel

Base-game-run.png

Création des classes de l’enfant

Une fois que nous avons créé la classe mère, qui établit la structure et certaines des fonctionnalités de notre application, il est temps de construire les classes du mode de jeu proprement dit, en utilisant la puissance de l’héritage

Classe de multiplication aléatoire

Cette classe exécutera le “premier mode” de notre jeu. Elle va utiliser le module random bien sûr, qui va nous donner la possibilité de demander à l’utilisateur des opérations aléatoires de 1 à 10. Voici un excellent article sur le module random (et d’autres modules importants) 😉

import random # Module pour les opérations aléatoires
class RandomMultiplication(BaseGame) :

 description = "Dans ce jeu, vous devez répondre correctement à la multiplication aléatoire : vous gagnez si vous atteignez 5 points, ou vous perdez si vous perdez toutes vos vies"

 def __init__(self) :
 # Le nombre de points nécessaires pour gagner est de 5
 # Passez l'argument 5 "points_to_win"
 super().__init__(5)

 def get_random_numbers(self) :

 first_number = random.randint(1, 10)
 second_number = random.randint(1, 10)

 return first_number, second_number
        
 def run(self) :
        
 # Appelez la classe supérieure pour imprimer les messages de bienvenue
 super().run()
        

 while self.lives > 0 and self.points_to_win > self.points :
 # Obtient deux nombres aléatoires
 number1, number2 = self.get_random_numbers()

 operation = f"{number1} x {number2} : "

 # Demande à l'utilisateur de répondre à cette opération
 # Prévient les erreurs de valeur
 user_answer = self.get_numeric_input(message=operation)

 if user_answer == number1 * number2 :
 print("\nVotre réponse est correcte\n")
                
 # Ajoute un point
 self.points = 1
 else :
 print("\nSorry, your answer is incorrect\n")

 # Substracts a live
 self.lives -= 1
            
 self.print_current_score()
 self.print_current_lives()
            
 # N'est exécuté que lorsque le jeu est terminé
 # Et qu'aucune des conditions n'est vraie
 else :
 # Imprime le message final
            
 if self.points >= self.points_to_win :
 self.print_win_message()
 else :
 self.print_lose_message(

)


Voici une autre classe massive 😅. Mais comme je l’ai déjà dit, ce n’est pas le nombre de lignes que cela prend, c’est à quel point c’est lisible et efficace. Et la meilleure chose à propos de Python est qu’il permet aux développeurs de faire du code propre et lisible comme s’ils parlaient un anglais normal

Cette classe a une particularité qui peut vous dérouter, mais je vais l’expliquer aussi simplement que possible

 # Classe mère
 def __init__(self, points_to_win, n_lives=3) :
 

“…


 # Classe enfant
 def __init__(self) :
 # Le nombre de points nécessaires pour gagner est de 5
 # Passez l'argument 5 "points_to_win"
 super().__init__(5

)
Le constructeur de la classe enfant appelle la fonction super qui, en même temps, fait référence à la classe mère (BaseGame). Cela revient à dire à Python

Remplissez l’attribut “points_to_win” de la classe mère avec 5 !

Il n’est pas nécessaire de mettre self dans la partie super().__init__() simplement parce que nous appelons super à l’intérieur du constructeur et que cela serait redondant

Nous utilisons également la fonction super dans la méthode run, et nous allons voir ce qui se passe dans ce morceau de code
#

 Méthode d'exécution de base
 Méthode parentale
 def run(self) :
 self.print_welcome_message()
        
 self.print_description()
 def run(self) :
        
 # Appelez la classe supérieure pour imprimer les messages de bienvenue
 super().run()
        
....

Comme vous pouvez le remarquer, la méthode run de la classe mère imprime les messages de bienvenue et de description. Mais c’est une bonne idée de conserver cette fonctionnalité et d’en ajouter d’autres dans les classes enfants. En conséquence, nous utilisons super pour exécuter tout le code de la méthode parent avant d’exécuter le morceau suivant

L’autre partie de la fonction run est assez simple. Elle demande à l’utilisateur un nombre avec le message de l’opération à laquelle il doit répondre. Ensuite, le résultat est comparé à la multiplication réelle et, s’ils sont égaux, ajoute un point, s’ils ne le sont pas, enlève 1 vie

Il convient de préciser que nous utilisons des boucles while-else. Cela dépasse le cadre de cet article mais j’en publierai un dans quelques jours

Enfin, get_random_numbers, utilise la fonction random.randint, qui renvoie un entier aléatoire dans l’intervalle spécifié. Elle renvoie ensuite un tuple de deux entiers aléatoires

Classe de multiplication aléatoire

Le “second mode” doit afficher le jeu sous la forme d’une table de multiplication, et s’assurer que l’utilisateur répond correctement à au moins deux tables

Pour ce faire, nous utiliserons à nouveau le pouvoir de super et modifierons l’attribut de la classe parente points_to_win à 2

class TableMultiplication(BaseGame) :

 description = "Dans ce jeu, vous devez résoudre correctement la table de multiplication complète. Vous gagnez si vous résolvez 2 tables"
    
 def __init__(self) :
 # Doit résoudre 2 tables pour gagner
 super().__init__(2)

 def run(self) :

 # Affiche les messages de bienvenue
 super().run()

 while self.lives > 0 and self.points_to_win > self.points :
 # Obtient deux nombres aléatoires
 number = random.randint(1, 10)

 for i in range(1, 11) :
                
 if self.lives <= 0 :
 # S'assure que le jeu ne peut pas continuer
 # si l'utilisateur épuise ses vies

 self.points = 0
 break
                
 operation = f"{number} x {i} : "

 user_answer = self.get_numeric_input(message=operation)

 if user_answer == number * i :
 print("Great ! Your answer is correct")
 else :
 print("Sorry your answer isn't correct")

 self.lives -= 1

 self.points = 1
            
 # N'est exécuté que lorsque le jeu est terminé
 # Et qu'aucune des conditions n'est vraie
 else :
 # Imprime le message final
            
 if self.points >= self.points_to_win :
 self.print_win_message()
 else :
 self.print_lose_message()

Comme vous pouvez le constater, nous ne modifions que la méthode run de cette classe. C’est la magie de l’héritage, nous écrivons une fois la logique que nous utilisons à plusieurs endroits, et nous l’oublions 😅

Dans la méthode run, nous utilisons une boucle for pour obtenir les nombres de 1 à 10 et nous construisons l’opération qui est montrée à l’utilisateur

Une fois de plus, si les vies sont épuisées ou si les points nécessaires pour gagner sont atteints, la boucle while s’interrompt et le message de victoire ou de défaite s’affiche

OUI, nous avons créé les deux modes de jeu, mais jusqu’à présent, si nous exécutons le programme, rien ne se passe

Finalisons donc le programme en implémentant le choix du mode et en instanciant les classes qui dépendent de ce choix

Implémentation du choix

L’utilisateur pourra choisir le mode de jeu qu’il souhaite utiliser. Voyons donc comment l’implémenter

if __name__ == "__main__" :

 print("Select Game mode")

 choice = input("[1],[2]: ")

 if choice == "1" :
 game = RandomMultiplication()
 elif choice == "2" :
 game = TableMultiplication()
 else :
 print("Please, select a valid game mode")
 exit()

 game.run()

Tout d’abord, nous demandons à l’utilisateur de choisir entre les modes 1 ou 2. Si l’entrée n’est pas valide, le script s’arrête. Si l’utilisateur choisit le premier mode, le programme exécutera le mode de jeu Multiplication aléatoire , et s’il choisit le second, le mode Multiplication de table sera exécuté

Voici à quoi cela ressemblerait

game.png

Conclusion

Félicitations, vous venez de construire une application Python avec la programmation orientée objet

Tout le code est disponible dans le dépôt Github

Dans cet article, vous avez appris à

  • Utiliser les constructeurs de classes Python
  • Créer une application fonctionnelle avec la POO
  • Utiliser la fonction super dans les classes Python
  • Appliquer les concepts de base de l’héritage
  • Implémenter les attributs de classe et d’instance

Bon codage 👨‍💻

Ensuite, explorez quelques-uns des meilleurs IDE Python pour améliorer votre productivité.

  • Daniel Diaz
    Auteur
Merci à nos sponsors
D'autres lectures intéressantes sur le développement
Alimentez votre entreprise
Quelques outils et services pour aider votre entreprise à se développer.
  • L'outil de synthèse vocale qui utilise l'IA pour générer des voix humaines réalistes.
    Essayez Murf AI
  • Web scraping, proxy résidentiel, proxy manager, web unlocker, search engine crawler, et tout ce dont vous avez besoin pour collecter des données web.
    Essayez Brightdata
  • Monday.com est un système d'exploitation tout-en-un qui vous aide à gérer vos projets, vos tâches, votre travail, vos ventes, votre CRM, vos opérations, vos flux de travail et bien plus encore.
    Essayez le lundi
  • Intruder est un scanner de vulnérabilité en ligne qui détecte les faiblesses de votre infrastructure en matière de cybersécurité, afin d'éviter des violations de données coûteuses.
    Essayer l'intrus