Python: Le module pickle
Comme son nom l'indique, enfin non, pas vraiment, le module pickle permet de sauvegarder dans un fichier, au format binaire, n'importe quel objet Python.
En clair, si pour une raison quelconque, dans un script Python, vous avez besoin de sauvegarder, temporairement ou même de façon plus pérenne, le contenu d'un objet Python comme une liste, un dictionnaire, un tuple etc etc ... au lieu d'utiliser une base de données ou un simple fichier texte, le module pickle est fait pour ça.
Il permet de stocker et de restaurer un objet Python tel quel sans aucune manipulation supplémentaire.
C'est vraiment super pratique.
Il fonctionne comme le module json mais n'est pas limité à un seul format d'objet.
Exemples:
>>> import pickle
>>> import string
>>> L = list(string.ascii_letters)
>>> print(L)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
>>> with open('mypicklefile', 'wb') as f1:
pickle.dump(L, f1)
>>> with open('mypicklefile', 'r') as f1:
f1.read()
'€\x03]q\x00(X\x01\x00\x00\x00aq\x01X\x01\x00\x00\x00bq\x02X\x01\x00\x00\x00cq\x03X\x01\x00\x00\x00dq\x04X\x01\x00\x00\x00eq\x05X\x01\x00\x00\x00fq\x06X\x01\x00\x00\x00gq\x07X\x01\x00\x00\x00hq\x08X\x01\x00\x00\x00iq\tX\x01\x00\x00\x00jq\nX\x01\x00\x00\x00kq\x0bX\x01\x00\x00\x00lq\x0cX\x01\x00\x00\x00mq\nX\x01\x00\x00\x00nq\x0eX\x01\x00\x00\x00oq\x0fX\x01\x00\x00\x00pq\x10X\x01\x00\x00\x00qq\x11X\x01\x00\x00\x00rq\x12X\x01\x00\x00\x00sq\x13X\x01\x00\x00\x00tq\x14X\x01\x00\x00\x00uq\x15X\x01\x00\x00\x00vq\x16X\x01\x00\x00\x00wq\x17X\x01\x00\x00\x00xq\x18X\x01\x00\x00\x00yq\x19X\x01\x00\x00\x00zq\x1aX\x01\x00\x00\x00Aq\x1bX\x01\x00\x00\x00Bq\x1cX\x01\x00\x00\x00Cq\x1dX\x01\x00\x00\x00Dq\x1eX\x01\x00\x00\x00Eq\x1fX\x01\x00\x00\x00Fq X\x01\x00\x00\x00Gq!X\x01\x00\x00\x00Hq"X\x01\x00\x00\x00Iq#X\x01\x00\x00\x00Jq$X\x01\x00\x00\x00Kq%X\x01\x00\x00\x00Lq&X\x01\x00\x00\x00Mq\'X\x01\x00\x00\x00Nq(X\x01\x00\x00\x00Oq)X\x01\x00\x00\x00Pq*X\x01\x00\x00\x00Qq+X\x01\x00\x00\x00Rq,X\x01\x00\x00\x00Sq-X\x01\x00\x00\x00Tq.X\x01\x00\x00\x00Uq/X\x01\x00\x00\x00Vq0X\x01\x00\x00\x00Wq1X\x01\x00\x00\x00Xq2X\x01\x00\x00\x00Yq3X\x01\x00\x00\x00Zq4e.'
>>> OL = None
>>> print(OL)
None
>>> with open('mypicklefile', 'rb') as f1:
OL = pickle.load(f1)
>>> type(OL)
<class 'list'>
>>> print(OL)
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
>>> L == OL
True
>>>
Dans l'exemple ci-dessus, j'ai créé une liste "L" contenant toutes les lettres de l'alphabet.
J'ai sauvegardé mon objet "L" (liste Python) dans un fichier "mypicklefile" grâce à la méthode dump du module pickle.
Précision importante, le module pickle écrit les données uniquement dans un fichier ouvert en mode binaire.
J'ai ouvert le fichier et afficher son contenu pour bien montrer que pickle écrit les données au format binaire.
J'ai créé un nouvel objet "OL" ayant None comme valeur (cette étape n'est pas obligatoire - uniquement pour montrer que l'objet "OL" n'existait pas auparavant).
J'ai ensuite chargé le contenu du fichier "mypicklefile" dans mon objet "OL" grâce à la méthode load du module pickle.
J'affiche le contenu de la nouvelle liste "OL" et le test d'égalité de l'objet "L" et "OL" pour bien montrer que les deux objets sont bien identiques.
La liste "OL" peut être modifiée (ajout, modification, suppression des valeurs) et à nouveau sauvegardée dans le fichier grâce à la méthode dump du module pickle pour une prochaine utilisation.
Petite précision, pour la méthode dump, le fichier doit être ouvert en mode 'wb' afin d'écraser le contenu précédent.
Si le fichier est ouvert en mode 'ab', les données sont écrites à la fin du fichier mais la méthode load récupère les données au début du fichier.
De toute manière, le mode append n'a aucun intérêt pour ce genre de stockage de données. On dump et on load l'intégralité du contenu d'un objet.
Et ça fonctionne pour tous types d'objets
Avec un tuple
>>> import pickle
>>> T = tuple(string.ascii_letters)
>>> T
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
>>> with open('mypicklefile', 'wb') as f1:
pickle.dump(T, f1)
>>> with open('mypicklefile', 'rb') as f1:
OT = pickle.load(f1)
>>> OT
('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
>>>
Avec un dictionnaire
>>> import pickle
>>> I = list(range(52))
>>> L = list(string.ascii_letters)
>>> D = {i: l for i, l in zip(I, L)}
>>> D
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>> with open('mypicklefile', 'wb') as f1:
pickle.dump(D, f1)
>>> with open('mypicklefile', 'rb') as f1:
OD = pickle.load(f1)
>>> OD
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e', 5: 'f', 6: 'g', 7: 'h', 8: 'i', 9: 'j', 10: 'k', 11: 'l', 12: 'm', 13: 'n', 14: 'o', 15: 'p', 16: 'q', 17: 'r', 18: 's', 19: 't', 20: 'u', 21: 'v', 22: 'w', 23: 'x', 24: 'y', 25: 'z', 26: 'A', 27: 'B', 28: 'C', 29: 'D', 30: 'E', 31: 'F', 32: 'G', 33: 'H', 34: 'I', 35: 'J', 36: 'K', 37: 'L', 38: 'M', 39: 'N', 40: 'O', 41: 'P', 42: 'Q', 43: 'R', 44: 'S', 45: 'T', 46: 'U', 47: 'V', 48: 'W', 49: 'X', 50: 'Y', 51: 'Z'}
>>>
Avec un deque (du module collections)
>>> import pickle
>>> from collections import deque
>>> L = list(string.ascii_letters)
>>> L
['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
>>> DE = deque(L)
>>> DE
deque(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])
>>> with open('mypicklefile', 'wb') as f1:
pickle.dump(DE, f1)
>>> with open('mypicklefile', 'rb') as f1:
ODE = pickle.load(f1)
>>> ODE
deque(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'])
>>>
Précision importante, la méthode load importe automatiquement l'objet nécessaire au chargement des données.
C'est à dire que dans l'exemple ci-dessus, l'objet deque du module collections n'a pas besoin d'être importé pour être correctement chargé via la méthode load. Il doit bien évidement être disponible dans la liste des modules de Python.
Et enfin, avec un objet perso
>>> class MyObject():
def __init__(self):
self.un = 1
self.deux = 2
self.trois = 3
def __repr__(self):
return "{}, {}, {}".format(self.un, self.deux, self.trois)
def __str__(self):
return "un: {}\ndeux: {}\ntrois: {}".format(self.un, self.deux, self.trois)
>>> A = MyObject()
>>> A
1, 2, 3
>>> print(A)
un: 1
deux: 2
trois: 3
>>> with open('mypicklefile', 'wb') as f1:
pickle.dump(A, f1)
>>> with open('mypicklefile', 'rb') as f1:
B = pickle.load(f1)
>>> B
1, 2, 3
>>> print(B)
un: 1
deux: 2
trois: 3
>>>
Dans ce cas, la class MyObject() doit être disponible pour pouvoir être utilisée via la méthode load sinon, une erreur "AttributeError" est levée.
Associé au module tempfile, nous avons un système complet de sauvegarde temporaire d'objets utilisable dans n'importe quel script Python.
Commentaires
OLIVE (non vérifié)
dim, 02/12/2018 - 14:36
Permalien
SUPER
Clair, net précis. Votre pense bête m'a fait lever des zones de flou sur l'utilisation du module pickle. J'ai aussi lu que l'on pouvait associé le module aux classe Pickler et Unpickler. Quel est l'intérêt d'utiliser ces 2 classes?
Merci
ronan
dim, 02/12/2018 - 23:24
Permalien
Merci beaucoup.
Pour la classe Pickler (et Unpickler), elle offre une méthode supplémentaire,
dispatch_table, mais j'avoue ne pas trop comprendre sa principale utilité.
Jean-Marc (non vérifié)
ven, 24/04/2020 - 14:24
Permalien
Félicitations
C'est parfaitement clair et même brillant. C'est la première fois que je trouve une telle leçon (dans tous les sens du mot). Merci très sincère et bravo
ronan
ven, 24/04/2020 - 14:34
Permalien
Merci
C'est gentil
croco (non vérifié)
jeu, 08/10/2020 - 09:18
Permalien
petite précision
Bonjour et merci pour cet éclairage.(limpide)
Les méthodes dump et load font appel à open, est il nécessaire de fermer explicitement les fichiers après lecture ou écriture?
Merci
ronan
jeu, 08/10/2020 - 09:53
Permalien
Très bonne question
J'avoue ne pas savoir.
Dans le doute, mieux vaut utiliser cette syntaxe:
Pour la lecture
Pour l'écriture
Je vais corriger mon article.
Jérémy (non vérifié)
mer, 06/01/2021 - 21:06
Permalien
Ouvrir un fichier 'mypicklefile' dans un dossier
Bonjour, est-il possible d'ouvrir un fichier pickle depuis un dossier ?
Si oui, comment ?
Merci.
ronan
mer, 06/01/2021 - 21:46
Permalien
C'est tout à fait possible
Grâce à la classe Path du module pathlib
Bonne continuation
MARC BONNET (non vérifié)
mer, 12/01/2022 - 18:22
Permalien
ajout fonctionnalité
il est possible de stocker une série d'objets dans le fichier pourvu qu'on ne le ferme pas. Lecture:
taille = os.stat(nomfichier).st_size
f=open(nomfichier,'rb')
while f.tell() < taille:
lobjet=pickle.load(f)
# faire qq chose
f.close()
ronan
jeu, 13/01/2022 - 08:23
Permalien
tout à fait d'accord
Il faut juste mémoriser l'ordre dans lequel les objets ont été enregistrés.
Vincent (non vérifié)
jeu, 02/02/2023 - 10:42
Permalien
methode pickle
Bonjour, est-ce qu'après l'utilisation du module 'pickle' pour lire ou sauvegarder un fichier en mode binaire (je suis en train de decouvrir cette commande) il faut "fermer" le fichier ('close') comme avec les methodes 'write' et 'read'?
ronan
jeu, 02/02/2023 - 21:29
Permalien
Fermeture du fichier
Bonjour,
Si tu utilises le "context management" grâce au mot clé "with" pour ouvrir le fichier avec la commande "open", il n'est pas nécessaire de le fermer après la lecture ou l'écriture.
Le fichier est automatiquement fermé.
Ajouter un commentaire