Dans cet article, vous allez créer une application de tables de multiplication en utilisant la puissance de la programmation orientée objet (POO) en Python.
Vous pratiquerez 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 que nous, en tant que développeurs, pouvons choisir la meilleure option pour chaque situation et problème. Lorsque nous parlons de programmation orientée objet, nous faisons référence à l’un des paradigmes les plus utilisés pour créer des applications évolutives au cours des dernières décennies.
Table des matières
Les bases de la POO
Nous allons jeter un coup d’œil rapide au concept le plus important de la POO 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 créés à la suite de 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.
# Instance objects of Book class blue_book = Book("The blue kid", "Blue") green_book = Book("The frog story", "Green")
Une bonne représentation de notre programme actuel serait :
Ce qui est génial, c’est que lorsque nous vérifions le type des instances blue_book et green_book, nous obtenons « Book ».
# Printing the type of the books print(type(blue_book)) # <class '__main__.Book'> print(type(green_book)) # <class '__main__.Book'>
Une fois ces concepts parfaitement clairs, nous pouvons commencer à construire le projet 😃.
Déclaration de projet
Lorsque vous travaillez en tant que développeurs/programmeurs, la plupart du temps n’est pas consacré à l’écriture de code, selon la newsstack nous ne passons qu’un tiers de notre temps à écrire ou refactoriser du code.
Nous avons passé les deux tiers restants à lire le code des autres et à analyser le problème sur lequel nous travaillons.
Donc, pour ce projet, je vais générer un énoncé de problème et nous analyserons comment créer notre application à partir de celui-ci. En conséquence, nous réalisons le processus complet, de la réflexion sur la solution à son application avec du code.
Un enseignant du primaire veut un jeu pour tester les compétences de 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 « perdre » si l’élève épuise toute sa vie.
Le jeu doit avoir deux modes, des multiplications aléatoires et des multiplications de table.
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 cela ne se produit pas, l’étudiant perd une vie 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 respective. Si l’élève échoue 3 fois, il perd, mais s’il complète deux tables, la partie 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 et conquérir
La compétence la plus importante en programmation est la résolution de problèmes. C’est parce que 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 résolus à la fois facilement et efficacement.
Donc, si vous avez besoin de créer un jeu, commencez par le décomposer en ses parties les plus importantes. Ces sous-problèmes seront beaucoup plus faciles à résoudre.
À ce moment-là, vous pouvez avoir la clarté sur la façon d’exécuter et d’intégrer tout avec du code.
Faisons donc un graphique de ce à quoi ressemblerait le jeu.
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 de table. Et la seule chose qu’ils partagent, ce sont les attributs Points et Vies.
Ayant toutes ces informations à l’esprit, entrons dans le code.
Création de la classe de jeu Parent
Lorsque nous travaillons avec la programmation orientée objet, nous recherchons le moyen le plus propre d’éviter la répétition de code. C’est appelé SEC (ne vous répétez pas).
Remarque : Cet objectif n’est pas lié à l’écriture du moins de lignes de code (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 souhaité des deux autres classes.
Voyons comment cela se ferait.
class BaseGame: # Lenght which the message is centered message_lenght = 60 description = "" def __init__(self, points_to_win, n_lives=3): """Base game class Args: points_to_win (int): the points the game will need to be finished n_lives (int): The number of lives the student have. Defaults to 3. """ self.points_to_win = points_to_win self.points = 0 self.lives = n_lives def get_numeric_input(self, message=""): while True: # Get the user input user_input = input(message) # If the input is numeric, return it # If it isn't, print a message and repeat if user_input.isnumeric(): return int(user_input) else: print("The input must be a number") continue def print_welcome_message(self): print("PYTHON MULTIPLICATION GAME".center(self.message_lenght)) def print_lose_message(self): print("SORRY YOU LOST ALL OF YOUR LIVES".center(self.message_lenght)) def print_win_message(self): print(f"CONGRATULATION YOU REACHED {self.points}".center(self.message_lenght)) def print_current_lives(self): print(f"Currently you have {self.lives} livesn") def print_current_score(self): print(f"nYour score is {self.points}") def print_description(self): print("nn" + self.description.center(self.message_lenght) + "n") # Basic run method def run(self): self.print_welcome_message() self.print_description()
Wow, cela semble une classe assez énorme. Permettez-moi de l’expliquer en profondeur.
Tout d’abord, comprenons les attributs de classe et le constructeur.
Fondamentalement, les attributs de classe sont des variables créées à l’intérieur de la classe, mais en dehors du constructeur ou de toute méthode.
Alors que les attributs d’instance sont des variables créées uniquement à l’intérieur du constructeur.
La principale différence entre ces deux est la portée. c’est-à-dire que les attributs de classe sont accessibles à la fois depuis un objet d’instance et depuis la classe. D’autre part, les attributs d’instance ne sont accessibles qu’à partir d’un objet d’instance.
game = BaseGame(5) # Accessing game message lenght class attr from class print(game.message_lenght) # 60 # Accessing the message_lenght class attr from class print(BaseGame.message_lenght) # 60 # Accessing the points instance attr from instance print(game.points) # 0 # Accesing the points instance attribute from class print(BaseGame.points) # Attribute error
Un autre article peut approfondir ce sujet. Restez en contact pour le lire.
La fonction get_numeric_input est utilisée pour empêcher l’utilisateur de fournir une entrée qui n’est pas numérique. Comme vous pouvez le remarquer, cette méthode est conçue pour demander à l’utilisateur jusqu’à ce qu’il obtienne une entrée numérique. Nous l’utiliserons plus tard dans les cours de l’enfant.
Les méthodes d’impression nous permettent d’éviter la répétition de l’impression de la même chose à chaque fois qu’un événement se produit dans le jeu.
Enfin, la méthode run n’est qu’un wrapper que les classes de multiplication aléatoire et de multiplication de table utiliseront pour interagir avec l’utilisateur et rendre tout fonctionnel.
Créer les classes de l’enfant
Une fois que nous avons créé cette classe parent, qui établit la structure et certaines des fonctionnalités de notre application, il est temps de créer les classes de mode de jeu réelles, en utilisant la puissance de l’héritage.
Classe de multiplication aléatoire
Cette classe exécutera le « premier mode » de notre jeu. Il va bien sûr utiliser le module random, ce qui nous donnera la possibilité de demander à l’utilisateur des opérations aléatoires de 1 à 10. Voici un excellent article sur le random (et d’autres modules importants) 😉.
import random # Module for random operations
class RandomMultiplication(BaseGame): description = "In this game you must answer the random multiplication correctlynYou win if you reach 5 points, or lose if you lose all your lives" def __init__(self): # The numbers of points needed to win are 5 # Pass 5 "points_to_win" argument 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): # Call the upper class to print the welcome messages super().run() while self.lives > 0 and self.points_to_win > self.points: # Gets two random numbers number1, number2 = self.get_random_numbers() operation = f"{number1} x {number2}: " # Asks the user to answer that operation # Prevent value errors user_answer = self.get_numeric_input(message=operation) if user_answer == number1 * number2: print("nYour answer is correctn") # Adds a point self.points += 1 else: print("nSorry, your answer is incorrectn") # Substracts a live self.lives -= 1 self.print_current_score() self.print_current_lives() # Only get executed when the game is finished # And none of the conditions are true else: # Prints the final message if self.points >= self.points_to_win: self.print_win_message() else: self.print_lose_message()
Voici un autre cours massif 😅. Mais comme je l’ai déjà dit, ce n’est pas le nombre de lignes qu’il faut, c’est à quel point c’est lisible et efficace. Et la meilleure chose à propos de Python est qu’il permet aux développeurs de créer un code propre et lisible comme s’ils parlaient un anglais normal.
Cette classe a une chose qui peut vous dérouter, mais je vais l’expliquer aussi simplement que possible.
# Parent class def __init__(self, points_to_win, n_lives=3): "... # Child class def __init__(self): # The numbers of points needed to win are 5 # Pass 5 "points_to_win" argument super().__init__(5)
Le constructeur de la classe enfant appelle la super fonction qui, en même temps, fait référence à la classe parent (BaseGame). Il s’agit essentiellement de dire à Python :
Remplissez l’attribut « points_to_win » de la classe mère avec 5 !
Il n’est pas nécessaire de mettre self, à l’intérieur de la partie super().__init__() simplement parce que nous appelons super à l’intérieur du constructeur, et cela entraînerait une redondance.
Nous utilisons également la fonction super dans la méthode run, et nous verrons ce qui se passe dans ce morceau de code.
# Basic run method # Parent method def run(self): self.print_welcome_message() self.print_description() def run(self): # Call the upper class to print the welcome messages super().run() .....
Comme vous pouvez le remarquer, la méthode run dans la classe parente affiche le message 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. Selon cela, nous utilisons super pour exécuter tout le code de la méthode parent avant d’exécuter la pièce suivante.
L’autre partie de la fonction run est assez simple. Il demande à l’utilisateur un numéro avec le message de l’opération auquel il doit répondre. Ensuite, le résultat est comparé à la multiplication réelle et s’ils sont égaux, ajoute un point, s’ils n’enlèvent pas 1 point de vie.
Cela vaut la peine de dire 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 la plage spécifiée. Ensuite, il renvoie un tuple de deux entiers aléatoires.
Classe de multiplication aléatoire
Le « deuxième mode », doit afficher le jeu sous forme de table de multiplication, et s’assurer que l’utilisateur répond correctement à au moins 2 tables.
Pour cela, nous utiliserons à nouveau la puissance de super et modifierons l’attribut de la classe mère points_to_win à 2.
class TableMultiplication(BaseGame): description = "In this game you must resolve the complete multiplication table correctlynYou win if you solve 2 tables" def __init__(self): # Needs to complete 2 tables to win super().__init__(2) def run(self): # Print welcome messages super().run() while self.lives > 0 and self.points_to_win > self.points: # Gets two random numbers number = random.randint(1, 10) for i in range(1, 11): if self.lives <= 0: # Ensure that the game can't continue # if the user depletes the lives 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 # Only get executed when the game is finished # And none of the conditions are true else: # Prints the final message 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, on écrit une fois la logique qu’on utilise à plusieurs endroits, et on l’oublie 😅.
Dans la méthode run, nous utilisons une boucle for pour obtenir les nombres de 1 à 10 et construisons l’opération qui est montrée à l’utilisateur.
Encore une fois, si les vies sont épuisées ou si les points nécessaires pour gagner sont atteints, la boucle while se rompra et le message de gain ou de perte s’affichera.
OUAIS, nous avons créé les deux modes de jeu, mais jusqu’à présent, si nous exécutons le programme, rien ne se passera.
Finalisons donc le programme en implémentant le choix de mode, et en instanciant les classes en fonction de ce choix.
Mise en œuvre du choix
L’utilisateur pourra choisir quel mode veut jouer. 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 1 ou 2 modes. Si l’entrée n’est pas valide, le script s’arrête. Si l’utilisateur sélectionne le premier mode, le programme exécutera le mode de jeu Random Multiplication, et s’il sélectionne le second, le mode de multiplication de table sera exécuté.
Voici à quoi cela ressemblerait.
Conclusion
Félicitations, vous venez de créer une application Python avec la programmation orientée objet.
Tout le code est disponible dans le Référentiel Github.
Dans cet article vous avez appris à :
- Utiliser les constructeurs de classes Python
- Créer une application fonctionnelle avec OOP
- Utiliser la super fonction 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 certains des meilleurs IDE Python pour une meilleure productivité.