Annonce

Réduire
Aucune annonce.

La sérialisation - COURS n°9

Réduire
Ceci est une discussion importante.
X
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • La sérialisation - COURS n°9

    La sérialisation


    PROBLÉMATIQUE

    Je souhaiterais ajouter à mon jeu, un tableau des 5 meilleurs scores et pour faire cela rien de tel que d'utiliser la sérialisation des données qui me permettront de rendre persistant mes scores dans le temps.

    Le principe est simple, vous avez une variable python (une liste par exemple) et voulez là garder en mémoire pour là réutiliser plus tard (par exemple au redémarrage du jeu)

    Quels outils utiliser avec le langage Python ?

    Un seul, on va utiliser le module pickle...

    Nous utiliserons le protocole 4, le dernier mise à jour et optimisé pour la version python (>= 3.4)

    Création de nos joueurs

    Pour avoir un tableau de scores, il nous faut des joueurs et leur score. Pour cela on va créer une liste de scores dont les noms des joueurs sont inconnus et les scores sont nuls.

    Code:
    from collections import namedtuple
    
    PLAYER_MAX = 5
    Player = namedtuple('Player', ['name', 'score'])
    
    def PlayersInit():
        players = []
        for i in range(PLAYER_MAX):
            p = Player(name='', score=0) # initialisation des joueurs au score 0
            players.append(p)
        return players
    Voilà une liste de joueurs initialisés comme dit précédemment... J'utilise les namedtuple, objet python simple à comprendre et qui correspond à un objet python que vous connaissez bien, les tuples ! La différence c'est que les namedtuple sont nommés !

    Ne vous inquiétez pas trop si vous ne connaissez pas, c'est plus pour vous donner une idée de conception si vous voulez fabriquer un tableau de scores, mais l'enjeu ici est d'expliquer comment sauvegarder et réutiliser ce tableau plus tard, lors d'un redémarrage du jeu par exemple...

    Ajout d'un nom de joueur et son score

    C'est une mise à jour du tableau, je vais l'appeler update !

    Code:
    def update(listPlayers, me):
        ''' 
            listPlayers est la liste des joueurs enregistrée
            me est un joueur, donc un objet de type Player
        '''
        
        for idx, player in enumerate(listPlayers):
            n, s = player.name, player.score
            if me.score > s: # si mon score dépasse l'ancien
                newList = [] # création de la liste updatée
                rightList = listPlayers[idx:]
                del rightList[-1] # suppression du dernier score à droite
                leftList = listPlayers[:idx] # récup des scores avant le score courant
                newList.extend(leftList) # ajout scores avant score courant
                newList.append(me) # ajout score courant
                newList.extend(rightList) # ajout scores après score courant
                listPlayers = newList[:] # copie dans listPlayers
                break # on quitte la boucle
        return listPlayers
    Bon c'est plus complexe, mais encore une fois, c'est pour résoudre une problématique ! C'est le principe de décalage, si vous êtes 1er, l'ex premier devient 2ème, etc... et le dernier dégage du tableau !

    Création de nouveaux joueurs

    Bon là j'ai pas cherché loin, j'ai ajouté 3 joueurs

    Code:
    Fred = Player(name='Fred', score=50) # Création d'un joueur + score pour test
    Dreamus = Player(name='Dreamus', score=35)
    Sakarov  = Player(name='Sakarov', score=40)
    Je les ai mis dans le désordre pour tester si ma mise en ordre dans le tableau est fonctionnel...

    Enregistrement dans le tableau

    Code:
    listPlayers = update(listPlayers, Fred) # Mise à jour du tableau de scores
    listPlayers = update(listPlayers, Dreamus)
    listPlayers = update(listPlayers, Sakarov) # on va voir si ça se met bien dans l'ordre décroissant
    Persistance des données, ENFIN !!!

    Oui vous le souhaitiez tellement fort que j'ai dû éviter des détails lors de l'écriture de ce tutoriel.

    On va utiliser le module pickle et ouvrir un fichier, s'il n'existe pas, le fichier sera créé automatiquement.

    Le principe ici, est la sauvegarde !

    Code:
    import pickle
    
    # ... suite du code
    
    def save(path):
        ''' path est le chemin du fichier '''
        with open(path, "wb") as f: # création + ouverture du fichier en mode binaire
            pickle.dump(listPlayers, f, 4) # sauvegarde de l'objet listPlayers dans le fichier f
    4 est le numéro de protocole dont je vous ai parlé au tout début du tutoriel.

    Non mais tu déconnes Fred, ça peut pas être aussi simple ? Eh bien si, rien de plus simple, on vient de sauvegarder dans le fichier avec le chemin absolu path, le tableau de scores...

    Ce qui rend le fichier très moche à lire

    fichier.jpg

    C'est bien si vous avez des mots de passe à enregistrer, mieux vaut que ça ne soit pas lisibles, n'est-ce pas ?

    C'est bien beau mais je fais quoi avec ce fichier maintenant ? On y arrive !

    Chargement du tableau de scores au démarrage du jeu

    Rien de compliquer, regardez !

    Code:
    def load(path):
        ''' path est le chemin du fichier '''
        var = None
        if os.path.exists(path): # Si le chemin existe
            try:
                with open(path, 'rb') as f: # on essaye d'ouvrir le fichier
                    var = pickle.load(f) # on charge notre liste dans la variable var
            except: pass # Sinon on fait rien, la valeur de var vaut None
        return var
    Bon j'ai ajouté des petites choses, histoire que mon jeu ne soit pas interrompu brusquement.

    Je l'appelle simplement de cette manière

    Code:
    listPlayers = load(".../sauvegarde.txt") # chargement des scores
    Un bel affichage en prime !

    Pour faire beau, niveau affichage, nous allons créer une forme joueur -> score

    Code:
    def displayScores():
        pattern = "{name} -> {score}" # format de l'affichage
        for player in listPlayers:
            name, score = player
            if name: # S'il y a un nom 
                print(pattern.format(name=name, score=score)) # on affiche le score
    Et là vous remarquez qu'exceptionnellement pour une fonction, j'ai utilisé print, car elle est réservée à l'affichage !

    Le code en entier

    Voilà c'est terminé, le code en entier vous permettra de tester et vérifier, n'hésitez pas à me prévenir si vous voyez des erreurs

    Code:
    from collections import namedtuple
    import pickle
    import os.path
    
    PLAYER_MAX = 5
    Player = namedtuple('Player', ['name', 'score'])
    
    def PlayersInit():
        players = []
        for i in range(PLAYER_MAX):
            p = Player(name='', score=0) # initialisation des joueurs au score 0
            players.append(p)
        return players
    
    def update(listPlayers, me):
        ''' 
            listPlayers est la liste des objets Player enregistrée
            me est un joueur, donc un objet de type Player
        '''
        
        for idx, player in enumerate(listPlayers):
            n, s = player.name, player.score
            if me.score > s: # si mon score dépasse l'ancien
                newList = [] # création de la liste updatée
                rightList = listPlayers[idx:]
                del rightList[-1] # suppression du dernier score à droite
                leftList = listPlayers[:idx] # récup des scores avant le score courant
                newList.extend(leftList) # ajout scores avant score courant
                newList.append(me) # ajout score courant
                newList.extend(rightList) # ajout scores après score courant
                listPlayers = newList[:] # copie dans listPlayers
                break # on quitte la boucle
        return listPlayers
    
    def save(path):
        ''' path est le chemin du fichier '''
        with open(path, "wb") as f: # création + ouverture du fichier en mode binaire
            pickle.dump(listPlayers, f, 4) # sauvegarde de l'objet listPlayers dans le fichier f
            
    def load(path):
        ''' path est le chemin du fichier '''
        var = None
        if os.path.exists(path): # Si le chemin existe
            try:
                with open(path, 'rb') as f: # on essaye d'ouvrir le fichier
                    var = pickle.load(f) # on charge notre liste dans la variable var
            except: pass # Sinon on fait rien, la valeur de var vaut None
        return var
    
    def displayScores():
        pattern = "{name} -> {score}" # format de l'affichage
        for player in listPlayers:
            name, score = player
            if name: # S'il y a un nom 
                print(pattern.format(name=name, score=score)) # on affiche le score
    
    listPlayers = PlayersInit() # Initialisation du tableau de scores
    
    # Ajout des nouveaux scores
    # -------------------------
    Fred = Player(name='Fred', score=50) # Création d'un joueur + score pour test
    Dreamus = Player(name='Dreamus', score=35)
    Sakarov  = Player(name='Sakarov', score=40)
    listPlayers = update(listPlayers, Fred) # Mise à jour du tableau de scores
    listPlayers = update(listPlayers, Dreamus)
    listPlayers = update(listPlayers, Sakarov) # on va voir si ça se met bien dans l'ordre décroissant
    
    save("/home/fred1599/Bureau/sauvegarde.txt") # sauvegarde des scores
    
    listPlayers = load("/home/fred1599/Bureau/sauvegarde.txt") # chargement des scores
    
    print(listPlayers) # Affichage de la liste des scores
    # [Player(name='Fred', score=50), Player(name='Sakarov', score=40), Player(name='Dreamus', score=35), Player(name='', score=0), Player(name='', score=0)]
    
    displayScores() # bel affichage des scores
    # Fred -> 50
    # Sakarov -> 40
    # Dreamus -> 35
    Merci de m'avoir lu et bonne journée...
    Dernière modification par fred, 23 juillet 2015, 08h46.

  • #2
    Salut,

    Alors déjà merci pour ce cours superbe. Franchement juste ce qu'il me fallais. je n'abordais pas la sauvegarde avec le module pickle j'étais plus basique.
    Mais je voudrais que tu m'explique plus amplement la partie
    J'ai compris que cela se comportais comme une BDD dans la partie mémoire du process qui peut être rappeler pour restaurer la partie engeager.
    pickle.dump(listPlayers, f, 4) # sauvegarde de l'objet listPlayers dans le fichier f

    J'ai bien compris le principe mais cela encrypte les résultats à la save et restart ?
    Moi j'ai du coup après test de ton code ceci en sortie sur le save.txt

    Code:
    €•k       ]”(Œ__main__”ŒPlayer”“”ŒFred”K2†”}”’”hŒSakarov”K(†”}”’”hŒDreamus”K#†”}”’”hŒ ”K †”}”’”hhK †”}”’”e.
    Je n'ai pas changer les données juste le path.

    Merci j'espère que tu suivra d'autres tutoriels de ce type car moi je me régale.
    J'aimerais beaucoup apprendre plus en avant la notion d'objet et surtout l'application graphique de python.
    Tu a bien compris que le C j'y reviendrais mais j'ai plus d'affinités et de facilité avec Python.
    Dernière modification par DreAmuS, 27 juillet 2015, 07h08.

    Commentaire


    • #3
      Moi j'ai du coup après test de ton code ceci en sortie sur le save.txt
      mais cela encrypte les résultats à la save et restart ?
      Oui j'ai même fais une copie d'écran dans mon cours, qui exprime ce que tu vois dans ton fichier...

      En fait le module enregistre dans un fichier binaire sous forme de flux de données (en général binaire, mais ASCII possible), un objet python.
      Il y a plusieurs protocole de 0 à 4, et certains il me semble, permettent de rendre lisible les informations écrites dans le fichier.

      Je peux guère t'en dire plus, la documentation est guère bavarde sur ce sujet.

      Commentaire


      • #4
        Merci de ta réponse Fred et pour le screen bien sur que je l'avais vu mais il est difficile de voir le contenu même en Zoomant. L'image étant trop petite.(je me fait vieux ^^)

        En tout cas rééllement sympa ce module et les fonctions qu'ils appliquent merci de l'info et de la technique pour l'utiliser.
        J'ai hâte de voir la suite. Sache que je suis un gourmand de python et j'essais vraiment de maitriser cet outil.

        Commentaire

        Chargement...
        X