• Assurez la sécurité des applications de la bonne manière! Détectez, protégez, surveillez, accélérez et plus encore…
  • Dans cet article, vous allez créer un  Application de tables de multiplication, en utilisant la puissance de la programmation orientée objet (POO) en Python.

    Vous pratiquerez les principaux concepts de POOet 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 problème. Lorsque nous parlons de programmation orientée objet, nous nous référons à l'un des paradigmes les plus utilisés pour créer des applications évolutives, au cours des dernières décennies.

    Les bases de la POO

    Nous allons jeter un coup d'œil sur le concept le plus important de la POO dans Python, les classes.

    A 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 Cas, qui ne sont que des objets individuels réalisé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 du livre de classe, nous devons appeler la classe et passer arguments à elle.

    # 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:

    Class.png

    Ce qui est génial, c'est que lorsque nous vérifions le type de livre bleu et livre vert  cas, nous obtenons «Book».

    # Printing the type of the books
    
    print(type(blue_book))
    # <class '__main__.Book'>
    print(type(green_book))
    # <class '__main__.Book'>

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

    Déclaration de projet

    Tout en travaillant en tant que développeurs / programmeurs, la plupart du temps n'est pas consacré à l'écriture de code, selon alorsewstack nous ne passons qu'un tiers de notre temps à écrire ou à refactoriser du code.

    Nous avons passé les deux autres tiers à lire le code des autres et analyser le problème nous travaillons.

    Donc, pour ce projet, je vais générer une déclaration 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 «perdu» si l'élève s'épuise toute sa vie.

    Le jeu doit avoir deux modes, des multiplications aléatoires et des multiplications de table.

    Le premier devrait donner à l'étudiant une multiplication aléatoire de 1 à 10, et il / elle doit répondre correctement pour gagner un point. Si cela ne se produit pas, l'étudiant perd un live 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'étudiant 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 peuvent ê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 piratage dans 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 diviser en parties les plus importantes. Ces sous-problèmes seront beaucoup plus faciles à résoudre.

    Juste à 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 le jeu ressemblerait.

    diviser et conquérir.png

    Ce graphique établit les relations entre les objets de notre application. Comme vous pouvez le voir, les deux objets principaux sont Multiplication aléatoire et 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 du code. C'est appelé SEC (ne vous répétez pas).

    Note : 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'abstrait des plus utilisées logique.

    Selon l'idée précédente, la classe parente 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} lives\n")
    
        def print_current_score(self):
            print(f"\nYour score is {self.points}")
    
        def print_description(self):
            print("\n\n" + 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. Laissez-moi vous l'expliquer en profondeur.

    Tout d'abord, comprenons le attributs de classe et le constructeur.

    Constructeur du jeu de base.png

    En gros, attributs de classe, sont des variables créées à l'intérieur de la classe, mais en dehors du constructeur ou de toute méthode.

    Tandis que 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 à partir d'un objet d'instance et de la classe. D'un autre côté, 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.

    Le  get_numeric_input La fonction 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.

    Base-game-input.png

    L'empreinte méthodes nous permettent de sauvegarder la répétition de l'impression de la même chose à chaque fois qu'un événement se produit dans le jeu.

    Dernier point mais non le moindre, le courir est juste un wrapper que le Multiplication aléatoire et Multiplication de table les classes utiliseront pour interagir avec l'utilisateur et rendre tout fonctionnel.

    Jeu de base run.png

    Créer les classes de l'enfant

    Une fois que nous avons créé cette classe parente, qui établit la structure et certaines fonctionnalités de notre application, il est temps de créer les classes de mode de jeu réelles, en utilisant la puissance de héritage.

    Classe de multiplication aléatoire

    Cette classe exécutera le «premier mode» de notre jeu. Il va utiliser le aléatoire module bien sûr, qui nous donnera la possibilité de demander à l'utilisateur des opérations aléatoires de 1 à 10. Ici est un excellent article sur l'aléatoire (et d'autres modules importants) 😉.

    import random # Module for random operations
    class RandomMultiplication(BaseGame):
    
        description = "In this game you must answer the random multiplication correctly\nYou 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 correct\n")
                    
                    # Adds a 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()
                
            # 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 une autre classe massive 😅. 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 le plus simplement 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 le super fonction qui, en même temps, fait référence à la classe parent (BaseGame). Il dit essentiellement à Python:

    Remplissez l'attribut «points_to_win» de la classe parente avec 5!

    Il n'est pas nécessaire de mettre soi, à l'intérieur de  super().__init__() partie simplement parce que nous appelons super à l'intérieur du constructeur, et cela entraînerait une redondance.

    Nous utilisons également le super fonction 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 remarquer la méthode run dans la classe parente, imprimez le message de bienvenue et de description. Mais c'est une bonne idée de conserver cette fonctionnalité et d'en ajouter des supplémentaires dans les classes enfants. Selon cela, nous utilisons super pour exécuter tout le code de la méthode parente avant d'exécuter le morceau suivant.

    L'autre partie de la fonction d'exécution 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 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 à ce sujet 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 dans un format 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 modifiez l'attribut de classe parent points_to_win à 2.

    class TableMultiplication(BaseGame):
    
        description = "In this game you must resolve the complete multiplication table correctly\nYou 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 vous en rendre compte, 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 que l'on utilise à plusieurs endroits, et on oublie ça 😅.

    Dans la méthode run, nous utilisons une boucle for pour obtenir les nombres de 1 à 10 et avons construit 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 gagnant ou perdant sera affiché.

    OUAIS, nous avons créé les deux modes du jeu, mais jusqu'à présent, si nous exécutons le programme, rien ne se passera.

    Alors finalisons le programme en implémentant le choix de mode et en instanciant les classes en fonction de ce choix.

    Choix de la mise en œuvre

    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 de s'exécuter. Si l'utilisateur sélectionne le premier mode, le programme exécutera le Multiplication aléatoire mode de jeu, et s'il sélectionne le second, le Multiplication de table le mode sera exécuté.

    Voici à quoi cela ressemblerait.

    game.png

    Conclusion

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

    Tout le code est disponible dans le Github référentiel.

    Dans cet article, vous avez appris à:

    • Utiliser les constructeurs de classe Python
    • Créer une application fonctionnelle avec la POO
    • Utilisez 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 meilleur IDE Python pour une meilleure productivité.