3.11 pickle --- Sérialisation d'objets de Python

Le module pickle implémente un algorithme basique mais puissant pour ``pickler'' (ou serialiser, marshaller ou aplatir) à peu près tous les types d'objets. C'est l'opération qui consiste à convertir des objets en un flux d'octets (et réciproquement : ``dépickler''). C'est une notion plus primitive que la persistance - bien que pickle lise et écrive des objets fichiers, il ne gère pas le problème de nommer les objets persistants, ni le domaine (encore plus compliqué) des accès concurrents aux objets persistants. Le module pickle peut transformer un objet complexe en un flux d'octets et il peut transformer le flux d'objet en un objet ayant la même structure interne. La chose la plus évidente à faire avec ces flux d'octets est de les écrire dans un fichier, mais il est aussi concevable de les envoyer sur un réseau ou de les stocker dans une base de données. Le module shelvefournit une interface simple pour pickler et dépickler des objets dans des fichiers de bases de données de style DBM.

Note: Le module pickle est plutôt lent. Une réimplémentation du même algorithme en C, qui est jusqu'à 1000 fois plus rapide, est disponible dans le module cPickle. Il a la même interface sauf que Pickler et Unpickler sont des fonctions usine, pas des classes (elles ne peuvent donc pas servir de classes de base pour l'héritage).

Bien que le module pickle puisse utiliser le module intégré marshal en interne, il diffère de marshal en ce sens qu'il gère certains types de données:

Le format de données utilisé par pickle est propre à Python. Ceci a pour avantage qu'il n'y a aucune restriction imposée par des standards externes tels que XDR (qui ne peut pas représenter le partage de pointeurs); cependant cela signifie que des programmes qui ne sont pas écrits en Python peuvent ne pas être capables de reconstituer des objets Python sérialisés.

Par défaut, le format de données de pickle utilise une représentation ASCII imprimable. C'est un peu plus volumineux qu'une représentation binaire. Le gros avantage d'utiliser de l'ASCII imprimable (et d'autres caractéristiques de la représentation utilisée par pickle) est que pour le débogage ou la récupération de données il est possible pour un humain de lire le fichier picklé avec un éditeur de texte standard.

Un format binaire, qui est légèrement plus efficace, peut être choisi en spécifiant une valeur différente de zéro (vraie) pour l'argument bin du constructeur de Pickler ou des fonctions dump() et dumps(). Le format binaire n'est pas le format par défaut pour rester compatible avec le module pickle de Python 1.4. Dans une version future il est possible que la valeur par défaut corresponde au format binaire.

Le module pickle ne gère pas les objets code, ce que fait le module marshal. Je suppose que pickle pourrait le faire, et peut-être le devrait-il, mais il n'y en a pas un grand besoin dans l'immédiat (aussi longtemps que marshal continue de servir à lire et écrire des objets code), et au moins cela évite la possibilité de faire entrer subrepticement des chevaux de Troie dans un programme.

A l'attention des modules de persistence écrits en se servant de pickle, il supporte la notion de référence à un objet en-dehors du flux de données picklées. De tels objets sont référencés par un nom, qui est une chaîne arbitraire de caractères ASCII imprimables. La résolution de tels noms n'est pas définie par le module pickle - le module d'objets persistants devra implémenter une méthode persistent_load(). Pour écrire des références à des objets persistants, le module persistant doit définir une méthode persistent_id() qui retourne soit None, soit l'ID persistant de l'objet.

Il y a quelques restrictions au picklage des instances de classes.

D'abord, la classe doit être définie au niveau supérieur dans un module. En outre, toutes ses variables d'instances doivent être picklable.

Quand une instance de classe picklée est dépicklée, sa méthode __init__() n'est normalement pas invoquée. Note: Ceci constitue une évolution par rapport aux versions précédentes de ce module; le changement a été introduit en Python 1.5b2. La raison du changement est que dans beaucoup de cas il est souhaitable d'avoir un constructeur qui requiert des arguments; c'est un inconvénient (mineur) d'avoir à fournir une méthode __getinitargs__().

S'il est souhaitable que la méthode __init__() soit appelée au moment du dépicklage, une classe doit définir une méthode __getinitargs__(), qui doit retourner un tuple contenant les arguments qui doivent être passés au constructeur de la classe (__init__()). Cette méthode est appelée au moment du picklage; le tuple qu'il retourne est incorporé dans le pickle de l'instance.

Les classes peuvent influencer plus profondément la façon dont leurs instances sont picklées - si la classe définit la méthode __getstate__(), elle est appelée et l'état de retour est picklé comme le contenu de l'instance, et si la classe définit la méthode __setstate__(), elle est appelée avec l'état dépicklé. (Notez que ces méthodes peuvent aussi servir à implémenter la copie des instances de classes.) S'il n'y a pas de méthode __getstate__(), le __dict__ de l'instance est picklé. S'il n'y a pas de méthode __setstate__(), l'objet picklé doit être un dictionnaire et ses éléments sont affectés au dictionnaire de la nouvelle instance. (Si une classe définit à la fois __getstate__() et __setstate__(), l'objet état n'a pas besoin d'être un dictionnaire - ces méthodes peuvent faire ce qu'elles veulent.) Ce protocole est aussi utilisé par les opérations de copie superficielle et profonde définies dans le module copy.

Notez que quand des instances de classes sont picklées, le code et les données de la classe ne sont pas picklées en même temps qu'elles. Seules les données d'instances sont picklées. Ceci est fait volontairement, pour que vous puissiez corriger des bogues dans une classe ou ajouter des méthodes et continuer de charger des objets qui ont été créés avec une version précédente de la classe. Si vous prévoyez de conserver longtemps des objets qui verront de nombreuses versions de la classe, il peut valoir le coup de mettre un numéro de version dans les objets de façon que les conversions adéquates puissent être faites par la méthode __setstate__() de la classse.

Quand une classe elle-même est picklée, seul son nom est picklé - la définition de la classe n'est pas picklée, mais réimportée par le processus de dépicklage. Par conséquent, la restriction qui impose que la classe soit définie au niveau supérieur dans un module s'applique aussi aux classes picklées.

L'interface peut être résumée de la façon suivante:

Pour pickler un objet x vers un fichier f, ouvert en écriture:

p = pickle.Pickler(f)
p.dump(x)

Ou, en raccourci:

pickle.dump(x, f)

Pour dépickler un objet x depuis un fichier f, ouvert en lecture:

u = pickle.Unpickler(f)
x = u.load()

En raccourci:

x = pickle.load(f)

La classe Pickler ne fait qu'appeler la méthode f.write() avec un argument chaîne. La classe Unpickler appelle la méthode f.read()(avec un argument entier) et f.readline() (sans argument), tous deux retournant une chaîne de caractères. Il est explicitement autorisé de passer des objets non fichiers ici, tant qu'ils ont les bonnes méthodes.

Le constructeur de la classe Pickler possède un second argument optionnel, bin. S'il est présent et vrai, le format de picklage binaire est utilisé; s'il est absent ou faux, le format de picklage texte (moins efficace, mais garantissant la compatibilité ascendante) est utilisé. La classe Unpickler ne possède pas d'argument pour distinguer entre les formats binaire et texte; il accepte les deux formats.

Les types suivants peuvent être picklés:

Les tentatives de pickler des objets impicklables déclenchent l'exception PicklingError; quand ceci se produit, un nombre indéterminé d'octets peut avoir été écrit dans le fichier.

Il est possible de réaliser des appels multiples à la méthode dump() de la même instance de Pickler. Ils doivent alors correspondre au même nombre d'appels de l'instance de Unpickler correspondante. Si le même objet est picklé par plusieurs appels à dump(), les appels à load() produiront tous des références vers le même objet. Avertissement: ceci est prévu pour pickler plusieurs objets sans que ces objets ou leurs parties aient subi des modifications. Si vous modifiez un objet et qu'ensuite vous le repicklez en vous servant de la même instance de Pickler, l'objet n'est pas repicklé - c'est une référence vers lui qui est picklée, et Unpickler retournera la vieille valeur, pas celle qui a été modifiée. (Deux problèmes ici: (a) détecter les changements, et (b) marshaller un ensemble minimal de changements. Je n'ai pas de réponse. Le ramassage de miettes peut aussi devenir un problème dans ce cas.)

A part les classes Pickler et Unpickler, le module définit les fonctions suivantes, et une exception:

dump(objet, fichier[, bin])
Ecrit une représentation picklée de objet dans l'objet fichier ouvert fichier. Cela équivaut à "Pickler(fichier, bin).dump(objet)". Si l'argument optionnel bin est présent et non nul, le format de picklage binaire est utilisé; s'il est nul ou absent, le format de picklage texte (moins efficace) est utilisé.

load(fichier)
Lit un objet picklé depuis l'objet fichier ouvert fichier. Ceci équivaut à "Unpickler(fichier).load()".

dumps(objet[, bin])
Retourne la représentation picklée de l'objet sous forme d'une chaîne de caractères, au lieu de l'écrire dans un fichier. Si l'argument optionnel bin est présent et non nul, le format de picklage binaire est utilisé; s'il est nul ou absent, le format de picklage texte (moins efficace) est utilisé.

loads(chaine)
Lit un objet picklé depuis une chaîne de caractères au lieu d'un fichier. Les caractères de la chaîne au-delà de la représentation picklée de l'objet sont ignorés.

PicklingError
Cette exception est déclenchée quand un objet impicklable est passé à Pickler.dump().

Voir aussi:

Module copy_reg:
déclare le constructeur de l'interface de pickle

Module shelve:
bases de données indexées d'objets; utilise pickle

Module copy:
copie superficielle et profonde d'objets

Module marshal:
sérialisation très efficace des types intégrés


Sous-sections
  1. Exemple