"pickle" --- Python object serialization
****************************************

**Code source :** Lib/pickle.py

======================================================================

The "pickle" module implements binary protocols for serializing and
de-serializing a Python object structure.  *"Pickling"* is the process
whereby a Python object hierarchy is converted into a byte stream, and
*"unpickling"* is the inverse operation, whereby a byte stream (from a
*binary file* or *bytes-like object*) is converted back into an object
hierarchy.  Pickling (and unpickling) is alternatively known as
"serialization", "marshalling," [1] or "flattening"; however, to avoid
confusion, the terms used here are "pickling" and "unpickling".

Avertissement:

  Le module "pickle" **n'est pas sécurisé**. Ne désérialisez des
  objets qu'à partir de sources fiables.Il est possible de produire
  des données binaires qui **exécutent du code arbitraire lors de leur
  désérialisation**. Ne désérialisez jamais des données provenant
  d'une source non fiable, ou qui pourraient avoir été
  modifiées.Pensez au module "hmac" pour signer des données afin de
  s'assurer qu'elles n'ont pas été modifiées.Des formats de
  sérialisation plus sûrs, comme "json", peuvent se révéler plus
  adaptés si vous travaillez sur des données qui ne sont pas fiables.
  Voir Comparaison avec json.


Relations aux autres modules Python
===================================


Comparaison avec "marshal"
--------------------------

Python has a more primitive serialization module called "marshal", but
in general "pickle" should always be the preferred way to serialize
Python objects.  "marshal" exists primarily to support Python's ".pyc"
files.

The "pickle" module differs from "marshal" in several significant
ways:

* "marshal" cannot be used to serialize user-defined classes and their
  instances.  "pickle" can save and restore class instances
  transparently, however the class definition must be importable and
  live in the same module as when the object was stored.

* The "marshal" serialization format is not guaranteed to be portable
  across Python versions.  Because its primary job in life is to
  support ".pyc" files, the Python implementers reserve the right to
  change the serialization format in non-backwards compatible ways
  should the need arise. The "pickle" serialization format is
  guaranteed to be backwards compatible across Python releases
  provided a compatible pickle protocol is chosen and pickling and
  unpickling code deals with Python 2 to Python 3 type differences if
  your data is crossing that unique breaking change language boundary.


Comparaison avec "json"
-----------------------

There are fundamental differences between the pickle protocols and
JSON (JavaScript Object Notation):

* *pickle* est un format binaire, tandis que JSON est un format
  textuel (constitué de caractères Unicode et généralement encodé en
  UTF-8) ;

* JSON peut être lu par une personne, contrairement à *pickle* ;

* JSON offre l'interopérabilité avec de nombreux outils en dehors de
  l'écosystème Python, alors que *pickle* est propre à Python ;

* Par défaut, JSON n'est capable de sérialiser qu'un nombre limité de
  types natifs Python, et ne prend pas en charge les classes définies
  par l'utilisateur. Le format *pickle* peut représenter une multitude
  de types d'objets, dont beaucoup automatiquement, grâce à une
  utilisation fine des possibilités d'introspection de Python ; on
  peut traiter les cas les plus complexes en implémentant des méthodes
  de sérialisation propres à une classe ;

* Contrairement à *pickle*, la désérialisation de données JSON n'ouvre
  pas en soi une vulnérabilité à l'exécution de code arbitraire.

Voir aussi:

  Le module "json" de la bibliothèque standard permet la sérialisation
  et désérialisation au format JSON.


Format du flux de données
=========================

The data format used by "pickle" is Python-specific.  This has the
advantage that there are no restrictions imposed by external standards
such as JSON (which can't represent pointer sharing); however it means
that non-Python programs may not be able to reconstruct pickled Python
objects.

By default, the "pickle" data format uses a relatively compact binary
representation.  If you need optimal size characteristics, you can
efficiently compress pickled data.

The module "pickletools" contains tools for analyzing data streams
generated by "pickle".  "pickletools" source code has extensive
comments about opcodes used by pickle protocols.

Il existe actuellement 6 protocoles différents pour la sérialisation.
Les protocoles portant les numéros les plus grands sont les derniers
ajoutés, et nécessitent en conséquence des versions de Python plus
récentes.

* Le protocole 0 est le format originel, humainement lisible. Il est
  rétrocompatible avec les versions les plus anciennes de Python.

* Le protocole 1 est un ancien format binaire, aussi compatible avec
  les versions anciennes.

* Protocol version 2 was introduced in Python 2.3.  It provides much
  more efficient pickling of *new-style classes*.  Refer to **PEP
  307** for information about improvements brought by protocol 2.

* Le protocole 3 a été introduit en Python 3.0. Il gère les objets
  "bytes", et ne permet pas la désérialisation par Python 2.x. Il fut
  le protocole par défaut de Python 3.0 à Python 3.7.

* Protocol version 4 was added in Python 3.4.  It adds support for
  very large objects, pickling more kinds of objects, and some data
  format optimizations.  This was the default protocol in Python 3.8--
  3.13. Refer to **PEP 3154** for information about improvements
  brought by protocol 4.

* Protocol version 5 was added in Python 3.8.  It adds support for
  out-of-band data and speedup for in-band data.  It is the default
  protocol starting with Python 3.14.  Refer to **PEP 574** for
  information about improvements brought by protocol 5.

Note:

  Serialization is a more primitive notion than persistence; although
  "pickle" reads and writes file objects, it does not handle the issue
  of naming persistent objects, nor the (even more complicated) issue
  of concurrent access to persistent objects.  The "pickle" module can
  transform a complex object into a byte stream and it can transform
  the byte stream into an object with the same internal structure.
  Perhaps the most obvious thing to do with these byte streams is to
  write them onto a file, but it is also conceivable to send them
  across a network or store them in a database.  The "shelve" module
  provides a simple interface to pickle and unpickle objects on DBM-
  style database files.


Interface du module
===================

Pour sérialiser un objet, contenant éventuellement d'autres objets,
appelez tout simplement la fonction "dumps()". La fonction "loads()",
quant à elle, désérialise un flux de données. Pour un contrôle plus
fin des opérations de sérialisation ou désérialisation, créez un objet
"Pickler" ou "Unpickler".

The "pickle" module provides the following constants:

pickle.HIGHEST_PROTOCOL

   Entier qui donne la version du protocole le plus récent qui soit
   disponible. Ce nombre peut être passé comme paramètre *protocol*
   aux fonctions "dump()" et "dumps()" ainsi qu'au constructeur de la
   classe "Pickler".

pickle.DEFAULT_PROTOCOL

   An integer, the default protocol version used for pickling.  May be
   less than "HIGHEST_PROTOCOL".  Currently the default protocol is 5,
   introduced in Python 3.8 and incompatible with previous versions.
   This version introduces support for out-of-band buffers, where
   **PEP 3118**-compatible data can be transmitted separately from the
   main pickle stream.

   Modifié dans la version 3.0: Le protocole par défaut est devenu le
   protocole 3.

   Modifié dans la version 3.8: Le protocole par défaut est devenu le
   protocole 4.

   Modifié dans la version 3.14: The default protocol is 5.

The "pickle" module provides the following functions to make the
pickling process more convenient:

pickle.dump(obj, file, protocol=None, *, fix_imports=True, buffer_callback=None)

   Écrit la représentation sérialisée de l'objet *obj* dans l'*objet
   fichier-compatible* *file*, qui doit être ouvert. Ceci est
   l'équivalent de "Pickle(file, protocol).dump(obj)".

   Les arguments *file*, *protocol*, *fix_imports* et
   *buffer_callback* sont identiques à ceux du constructeur de la
   classe "Pickler".

   Modifié dans la version 3.8: ajout de l'argument *buffer_callback*.

pickle.dumps(obj, protocol=None, *, fix_imports=True, buffer_callback=None)

   Renvoie la représentation sérialisée de *obj* sous forme de
   "bytes", au lieu de l'écrire dans un fichier.

   Les arguments *protocol*, *fix_imports* et *buffer_callback* sont
   identiques à ceux du constructeur de la classe "Pickler".

   Modifié dans la version 3.8: ajout de l'argument *buffer_callback*.

pickle.load(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

   Charge la représentation sérialisée d'un objet depuis l'*objet
   fichier-compatible* ouvert *file*, et renvoie l'objet reconstitué
   obtenu. Ceci est l'équivalent de "Unpickler(file).load()".

   La version du protocole utilisée pour la sérialisation est détectée
   automatiquement, d'où l'absence d'un argument. Les octets situés
   après la représentation sérialisée de l'objet sont ignorés.

   Les arguments *file*, *fix_imports*, *encoding*, *errors*, *strict*
   et *buffers* sont identiques à ceux du constructeur de la classe
   "Unpickler".

   Modifié dans la version 3.8: Ajout de l'argument *buffers*.

pickle.loads(data, /, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

   Renvoie l'objet reconstitué à partir de la représentation
   sérialisée *data*, qui doit être fournie sous la forme d'un *bytes-
   like object*.

   La version du protocole utilisée pour la sérialisation est détectée
   automatiquement, d'où l'absence d'un argument. Les octets situés
   après la représentation sérialisée de l'objet sont ignorés.

   Arguments *fix_imports*, *encoding*, *errors*, *strict* and
   *buffers* have the same meaning as in the "Unpickler" constructor.

   Modifié dans la version 3.8: Ajout de l'argument *buffers*.

The "pickle" module defines three exceptions:

exception pickle.PickleError

   Common base class for the other pickling exceptions.  It inherits
   from "Exception".

exception pickle.PicklingError

   Error raised when an unpicklable object is encountered by
   "Pickler". It inherits from "PickleError".

   Lisez Quels objets sont sérialisables ? pour en savoir plus sur les
   types d'objets qui peuvent être sérialisés.

exception pickle.UnpicklingError

   Error raised when there is a problem unpickling an object, such as
   a data corruption or a security violation.  It inherits from
   "PickleError".

   Veuillez noter que d'autres exceptions peuvent être levées durant
   la désérialisation, comme "AttributeError", "EOFError",
   "ImportError" et "IndexError" (liste non-exhaustive).

The "pickle" module exports three classes, "Pickler", "Unpickler" and
"PickleBuffer":

class pickle.Pickler(file, protocol=None, *, fix_imports=True, buffer_callback=None)

   Classe d'objets qui implémentent la sérialisation vers un flux
   binaire.

   L'argument optionnel *protocol* détermine la version du protocole
   de sérialisation à employer, entre 0 et "HIGHEST_PROTOCOL". La
   valeur par défaut est celle de "DEFAULT_PROTOCOL". Avec un nombre
   strictement négatif, c'est "HIGHEST_PROTOCOL" qui est utilisé.

   L'argument *file* peut être un fichier sur disque ouvert en mode
   binaire pour l'écriture, une instance de la classe "io.BytesIO", ou
   plus généralement un objet quelconque qui possède une méthode
   "write()" acceptant d'être appelée sur un argument unique de type
   "bytes".

   Si *fix_imports* est vrai et *protocol* est inférieur ou égal à 2,
   les noms des modules sont reliés par *pickle* aux anciens noms qui
   avaient cours en Python 2, afin que le flux sérialisé soit lisible
   aussi bien par Python 2 que Python 3.

   If *buffer_callback* is "None" (the default), buffer views are
   serialized into *file* as part of the pickle stream.

   If *buffer_callback* is not "None", then it can be called any
   number of times with a buffer view.  If the callback returns a
   false value (such as "None"), the given buffer is out-of-band;
   otherwise the buffer is serialized in-band, i.e. inside the pickle
   stream.

   It is an error if *buffer_callback* is not "None" and *protocol* is
   "None" or smaller than 5.

   Modifié dans la version 3.8: ajout de l'argument *buffer_callback*.

   dump(obj)

      Écrit la représentation sérialisée de l'objet *obj* dans le
      fichier ouvert passé au constructeur.

   persistent_id(obj)

      Ne fait rien par défaut. Cette méthode est destinée à être
      implémentée par une classe fille.

      Si "persistent_id()" renvoie "None", *obj* est sérialisé
      normalement. Toute autre valeur est reprise par le "Pickler"
      comme ID persistant pour *obj*. Le sens de cet ID persistant
      doit être défini par "Unpickler.persistent_load()". Veuillez
      noter que la valeur renvoyée par "persistent_id()" ne peut pas
      porter elle-même d'ID persistant.

      La section Persistance d'objets externes donne des détails et
      exemples.

      Modifié dans la version 3.13: Add the default implementation of
      this method in the C implementation of "Pickler".

   dispatch_table

      A pickler object's dispatch table is a registry of *reduction
      functions* of the kind which can be declared using
      "copyreg.pickle()".  It is a mapping whose keys are classes and
      whose values are reduction functions.  A reduction function
      takes a single argument of the associated class and should
      conform to the same interface as a "__reduce__()" method.

      Lorsqu'un sérialiseur ne possède pas l'attribut
      "dispatch_table", comme c'est le cas par défaut, il utilise le
      tableau global du module "copyreg". Afin de personnaliser
      l'opération de sérialisation pour un sérialiseur particulier, on
      peut affecter à son attribut "dispatch_table" un objet
      compatible avec les dictionnaires. Une autre possibilité est de
      définir l'attribut "dispatch_table" dans une classe fille de
      "Pickler". Sa valeur sera alors utilisée pour toutes les
      instances de cette classe fille.

      Voir Tables de distribution pour des exemples d'utilisation.

      Ajouté dans la version 3.3.

   reducer_override(obj)

      Special reducer that can be defined in "Pickler" subclasses.
      This method has priority over any reducer in the
      "dispatch_table".  It should conform to the same interface as a
      "__reduce__()" method, and can optionally return
      "NotImplemented" to fallback on "dispatch_table"-registered
      reducers to pickle "obj".

      Voir Réduction personnalisée pour les types, fonctions et autres
      objets pour un exemple détaillé.

      Ajouté dans la version 3.8.

   fast

      Cet attribut est obsolète. Une valeur vraie (« mode rapide »)
      désactive la mémorisation des objets au fur et à mesure de leur
      sérialisation, qui permet habituellement de représenter les
      doublons par une unique référence. Cette option accélère la
      sérialisation en évitant des *opcodes* PUT superflus. Elle ne
      doit pas être utilisée sur un objet contenant une référence à
      lui-même, car le "Pickler" entre alors dans une récursion
      infinie.

      Utilisez plutôt "pickletools.optimize()" pour obtenir des
      données sérialisées plus compactes.

   clear_memo()

      Clears the pickler's "memo".

      The memo is the data structure that remembers which objects the
      pickler has already seen, so that shared or recursive objects
      are pickled by reference and not by value.  This method is
      useful when re-using picklers.

class pickle.Unpickler(file, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)

   Les objets de cette classe sont des désérialiseurs, qui lisent un
   flux de données pour le convertir en objet.

   Il n'y a nul besoin d'argument *protocol*. La version du protocole
   avec lequel sont encodées les données est déterminée
   automatiquement.

   L'argument *file* doit posséder trois méthodes qui proviennent de
   l'interface de "io.BufferedIOBase". Ce sont : "read()", prenant un
   entier, "readinto()", prenant un tampon, et "readline()", sans
   arguments. *file* peut donc être aussi bien un fichier sur disque
   ouvert en mode lecture binaire qu'un objet "io.BytesIO", ou un
   objet quelconque vérifiant ces critères.

   Les paramètres facultatifs *fix_imports*, *encoding* et *errors*
   sont dédiés à la compatibilité de la désérialisation avec les flux
   binaires générés par Python 2. Si *fix_imports* est vrai, *pickle*
   tente de modifier les anciens noms des modules que l'on trouve en
   Python 2, pour les remplacer par ceux en usage en Python 3. Les
   paramètres *encoding* et *errors* contrôlent la façon de décoder
   les chaînes de caractères 8 bits. Leurs valeurs par défaut
   respectives sont "'ASCII'" et "'strict'". *encoding* peut être mis
   à "'bytes'" pour lire des chaînes d'octets en tant que *bytes*. Il
   doit être mis à "'latin1'" pour désérialiser des tableaux NumPy ou
   des instances de "datetime", "date" et "time" sérialisées par
   Python 2.

   If *buffers* is "None" (the default), then all data necessary for
   deserialization must be contained in the pickle stream.  This means
   that the *buffer_callback* argument was "None" when a "Pickler" was
   instantiated (or when "dump()" or "dumps()" was called).

   If *buffers* is not "None", it should be an iterable of buffer-
   enabled objects that is consumed each time the pickle stream
   references an out-of-band buffer view.  Such buffers have been
   given in order to the *buffer_callback* of a Pickler object.

   Modifié dans la version 3.8: Ajout de l'argument *buffers*.

   load()

      Lit la représentation sérialisée d'un objet depuis le fichier
      ouvert passé au constructeur, et reconstitue l'objet qui y est
      stocké, avec tous les objets qu'il contient. Les octets situés
      au-delà de la fin de la représentation binaire sont ignorés.

   persistent_load(pid)

      Par défaut, cette méthode lève une exception "UnpicklingError".

      Si elle est définie autrement dans une sous-classe,
      "persistent_load()" doit renvoyer l'objet correspondant à l'ID
      persistant *pid*. Si celui-ci est invalide, elle doit lever une
      exception "UnpicklingError".

      La section Persistance d'objets externes donne des détails et
      exemples.

      Modifié dans la version 3.13: Add the default implementation of
      this method in the C implementation of "Unpickler".

   find_class(module, name)

      Importe *module* si besoin, et renvoie l'objet du nom *name*
      qu'il contient. *module* et *name* sont des chaînes de
      caractères (classe "str"). Contrairement à ce que son nom laisse
      penser, "find_class()" est également appelée pour trouver les
      fonctions.

      Les classes filles peuvent redéfinir cette méthode pour
      restreindre la désérialisation à certains types d'objets ou à
      d'autres conditions, notamment en vue de réduire les risques de
      sécurité. Voir Restriction des noms dans l'espace de nommage
      global pour plus de détails.

      Lève un événement d'audit "pickle.find_class" avec les arguments
      "module" et "name".

class pickle.PickleBuffer(buffer)

   Encapsule un objet tampon contenant des données sérialisables.
   *buffer* doit être un objet prenant en charge le protocole tampon,
   comme un *objet octet-compatible* ou un tableau n-dimensionnel.

   Les objets "PickleBuffer" savent gérer le protocole tampon. Il est
   donc possible de les passer à d'autres API qui attendent un tampon,
   comme "memoryview".

   Les objets "PickleBuffer" ne peuvent être sérialisés qu'avec le
   protocole 5 ou supérieur. Ils sont susceptibles d'être sérialisés
   hors-bande.

   Ajouté dans la version 3.8.

   raw()

      Renvoie une "memoryview" de l'espace mémoire sous-jacent à ce
      tampon. La *memoryview* renvoyée est unidimensionnelle et
      C-contiguë. Elle a le format "B" (octets sans signe).
      "BufferError" est levée si le tampon n'est ni C-contigu, ni
      Fortran-contigu.

   release()

      Release the underlying buffer exposed by the PickleBuffer
      object.


Quels objets sont sérialisables ?
=================================

Les objets des types suivants peuvent être sérialisés :

* built-in constants ("None", "True", "False", "Ellipsis", and
  "NotImplemented");

* integers, floating-point numbers, complex numbers;

* strings, bytes, bytearrays;

* tuples, lists, sets, and dictionaries containing only picklable
  objects;

* functions (built-in and user-defined) accessible from the top level
  of a module (using "def", not "lambda");

* classes accessible from the top level of a module;

* instances of such classes for which the result of calling
  "__getstate__()" is picklable  (see section Sérialisation des
  instances d'une classe for details).

Si vous essayez de sérialiser un objet qui ne peut pas l'être, une
exception de type "PicklingError" est levée. Lorsque cela se produit,
il est possible qu'un certain nombre d'octets aient déjà été écrits
dans le fichier ou flux. La sérialisation d'une structure de donnée
avec de nombreux niveaux d'imbrication peut lever une exception
"RecursionError". Pour augmenter la limite (avec précaution), voir
"sys.setrecursionlimit()".

Note that functions (built-in and user-defined) are pickled by fully
*qualified name*, not by value. [2]  This means that only the function
name is pickled, along with the name of the containing module and
classes.  Neither the function's code, nor any of its function
attributes are pickled.  Thus the defining module must be importable
in the unpickling environment, and the module must contain the named
object, otherwise an exception will be raised. [3]

Similarly, classes are pickled by fully qualified name, so the same
restrictions in the unpickling environment apply.  Note that none of
the class's code or data is pickled, so in the following example the
class attribute "attr" is not restored in the unpickling environment:

   class Foo:
       attr = 'A class attribute'

   picklestring = pickle.dumps(Foo)

These restrictions are why picklable functions and classes must be
defined at the top level of a module.

Similarly, when class instances are pickled, their class's code and
data are not pickled along with them.  Only the instance data are
pickled.  This is done on purpose, so you can fix bugs in a class or
add methods to the class and still load objects that were created with
an earlier version of the class.  If you plan to have long-lived
objects that will see many versions of a class, it may be worthwhile
to put a version number in the objects so that suitable conversions
can be made by the class's "__setstate__()" method.


Sérialisation des instances d'une classe
========================================

Dans cette section sont décrits les mécanismes généraux qui s'offrent
à vous pour définir, personnaliser et contrôler la manière dont les
instances d'une classe sont sérialisées et désérialisées.

In most cases, no additional code is needed to make instances
picklable.  By default, pickle will retrieve the class and the
attributes of an instance via introspection. When a class instance is
unpickled, its "__init__()" method is usually *not* invoked.  The
default behaviour first creates an uninitialized instance and then
restores the saved attributes.  The following code shows an
implementation of this behaviour:

   def save(obj):
       return (obj.__class__, obj.__dict__)

   def restore(cls, attributes):
       obj = cls.__new__(cls)
       obj.__dict__.update(attributes)
       return obj

Les classes peuvent personnaliser le comportement par défaut en
définissant des méthodes spéciales :

object.__getnewargs_ex__()

   In protocols 2 and newer, classes that implement the
   "__getnewargs_ex__()" method can dictate the values passed to the
   "__new__()" method upon unpickling.  The method must return a pair
   "(args, kwargs)" where *args* is a tuple of positional arguments
   and *kwargs* a dictionary of named arguments for constructing the
   object.  Those will be passed to the "__new__()" method upon
   unpickling.

   Définissez cette méthode seulement si la méthode "__new__()" de
   votre classe demande des arguments nommés. Dans le cas contraire,
   mieux vaut définir "__getnewargs__()" pour préserver la
   compatibilité avec les protocoles anciens.

   Modifié dans la version 3.6: "__getnewargs_ex__()" est désormais
   appelée dans les protocoles 2 et 3.

object.__getnewargs__()

   Comme "__getnewargs_ex__()", mais ne permet que les arguments
   positionnels. Cette méthode doit renvoyer le *n*-uplet "args" des
   arguments passés à "__new__()" lors de la désérialisation : l'appel
   sera "classe.__new__(*args)".

   Si "__getnewargs_ex__()" est définie, elle prend la priorité et
   "__getnewargs__()" n'est jamais appelée.

   Modifié dans la version 3.6: Auparavant, "__getnewargs__()" était
   appelée au lieu de "__getnewargs_ex__()" dans les protocoles 2 et
   3.

object.__getstate__()

   Classes can further influence how their instances are pickled by
   overriding the method "__getstate__()".  It is called and the
   returned object is pickled as the contents for the instance,
   instead of a default state. There are several cases:

   * For a class that has no instance "__dict__" and no "__slots__",
     the default state is "None".

   * For a class that has an instance "__dict__" and no "__slots__",
     the default state is "self.__dict__".

   * For a class that has an instance "__dict__" and "__slots__", the
     default state is a tuple consisting of two dictionaries:
     "self.__dict__", and a dictionary mapping slot names to slot
     values.  Only slots that have a value are included in the latter.

   * For a class that has "__slots__" and no instance "__dict__", the
     default state is a tuple whose first item is "None" and whose
     second item is a dictionary mapping slot names to slot values
     described in the previous bullet.

   Modifié dans la version 3.11: Added the default implementation of
   the "__getstate__()" method in the "object" class.

object.__setstate__(state)

   Lors de la désérialisation, l'état de l'instance est passé à la
   méthode "__setstate__()", si elle est définie (l'objet *state* n'a
   pas besoin d'être un dictionnaire). Si elle ne l'est pas, les
   attributs de l'objet sont tirés de l'état, qui dans ce cas doit
   être obligatoirement un dictionnaire.

   Note:

     If "__reduce__()" returns a state with value "None" at pickling,
     the "__setstate__()" method will not be called upon unpickling.

Refer to the section Traitement des objets à état for more information
about how to use the methods "__getstate__()" and "__setstate__()".

Note:

  At unpickling time, some methods like "__getattr__()",
  "__getattribute__()", or "__setattr__()" may be called upon the
  instance.  In case those methods rely on some internal invariant
  being true, the type should implement "__new__()" to establish such
  an invariant, as "__init__()" is not called when unpickling an
  instance.

As we shall see, pickle does not use directly the methods described
above.  In fact, these methods are part of the copy protocol which
implements the "__reduce__()" special method.  The copy protocol
provides a unified interface for retrieving the data necessary for
pickling and copying objects. [4]

Although powerful, implementing "__reduce__()" directly in your
classes is error prone.  For this reason, class designers should use
the high-level interface (i.e., "__getnewargs_ex__()",
"__getstate__()" and "__setstate__()") whenever possible.  We will
show, however, cases where using "__reduce__()" is the only option or
leads to more efficient pickling or both.

object.__reduce__()

   Voici l'interface de la méthode "__reduce__()". Elle ne prend aucun
   argument et renvoie soit une chaîne de caractères, soit (c'est
   conseillé) un *n*-uplet. On appelle souvent l'objet renvoyé «
   valeur de réduction ».

   If a string is returned, the string should be interpreted as the
   name of a global variable.  It should be the object's local name
   relative to its module; the pickle module searches the module
   namespace to determine the object's module.  This behaviour is
   typically useful for singletons.

   Si c'est un *n*-uplet qui est renvoyé, ses éléments sont
   interprétés dans l'ordre comme suit. Les deux premiers éléments
   sont obligatoires, les quatre suivants sont facultatifs et peuvent
   être simplement omis, ou bien mis à "None". Les éléments sont, dans
   l'ordre :

   * Un objet appelable qui sera appelé pour créer l'objet initial.

   * Un *n*-uplet d'arguments passés à cet objet appelable. Donnez un
     *n*-uplet vide si l'objet appelable n'accepte pas d'arguments.

   * L'état de l'objet, qui sera passé à la méthode "__setstate__()"
     comme vu précédemment. Si la méthode n'existe pas, cet élément
     doit être un dictionnaire, et ses éléments compléteront
     l'attribut "__dict__".

   * Optionally, an iterator (and not a sequence) yielding successive
     items. These items will be appended to the object either using
     "obj.append(item)" or, in batch, using
     "obj.extend(list_of_items)". This is primarily used for list
     subclasses, but may be used by other classes as long as they have
     "append()" and "extend()" methods with the appropriate signature.
     (Whether "append()" or "extend()" is used depends on which pickle
     protocol version is used as well as the number of items to
     append, so both must be supported.)

   * Un itérateur (non pas une séquence). Les éléments qu'il fournit
     doivent être des couples "(clé, valeur)". Ils sont ajoutés dans
     l'objet par affectation aux clés : "objet[clé] = valeur". Ceci
     est principalement utile aux classes héritant de "dict", mais
     peut servir à d'autres classes à la seule condition qu'elles
     implémentent la méthode "__setitem__()".

   * Un objet appelable qui puisse recevoir en arguments l'objet et
     son état. Ceci permet de redéfinir le processus de reconstruction
     des attributs pour un objet en particulier, outrepassant la
     méthode "__setstate__()". Si cet objet appelable est fourni,
     "__setstate__()" n'est pas appelée.

     Ajouté dans la version 3.8: ajout du sixième élément.

object.__reduce_ex__(protocol)

   Il est également possible de définir une méthode "__reduce_ex__()".
   La seule différence est qu'elle prend la version du protocole en
   argument. Si elle est définie, elle prend le pas sur
   "__reduce__()". De plus, "__reduce__()" devient automatiquement un
   alias pour sa version étendue. Cette méthode est principalement
   destinée à renvoyer des valeurs de réduction compatibles avec les
   versions anciennes de Python.


Persistance d'objets externes
-----------------------------

For the benefit of object persistence, the "pickle" module supports
the notion of a reference to an object outside the pickled data
stream.  Such objects are referenced by a persistent ID, which should
be either a string of alphanumeric characters (for protocol 0) [5] or
just an arbitrary object (for any newer protocol).

The resolution of such persistent IDs is not defined by the "pickle"
module; it will delegate this resolution to the user-defined methods
on the pickler and unpickler, "persistent_id()" and
"persistent_load()" respectively.

Pour affecter à des objets leurs ID persistants provenant d'une source
externe, le sérialiseur doit posséder une méthode "persistent_id()"
qui prend un objet et renvoie soit "None", soit son ID. Si cette
méthode renvoie "None", l'objet est sérialisé de la manière
habituelle. Si un ID est renvoyé, sous forme de chaîne de caractères,
c'est cette chaîne qui est sérialisée et elle est marquée de manière
spéciale pour être reconnue comme un ID persistant.

Pour désérialiser des objets identifiés par un ID externe, un
désérialiseur doit posséder une méthode "persistent_load()" qui prend
un ID et renvoie l'objet qu'il désigne.

Voici un exemple complet qui montre comment sérialiser des objets
externes en leur affectant des ID persistants.

   # Simple example presenting how persistent ID can be used to pickle
   # external objects by reference.

   import pickle
   import sqlite3
   from collections import namedtuple

   # Simple class representing a record in our database.
   MemoRecord = namedtuple("MemoRecord", "key, task")

   class DBPickler(pickle.Pickler):

       def persistent_id(self, obj):
           # Instead of pickling MemoRecord as a regular class instance, we emit a
           # persistent ID.
           if isinstance(obj, MemoRecord):
               # Here, our persistent ID is simply a tuple, containing a tag and a
               # key, which refers to a specific record in the database.
               return ("MemoRecord", obj.key)
           else:
               # If obj does not have a persistent ID, return None. This means obj
               # needs to be pickled as usual.
               return None


   class DBUnpickler(pickle.Unpickler):

       def __init__(self, file, connection):
           super().__init__(file)
           self.connection = connection

       def persistent_load(self, pid):
           # This method is invoked whenever a persistent ID is encountered.
           # Here, pid is the tuple returned by DBPickler.
           cursor = self.connection.cursor()
           type_tag, key_id = pid
           if type_tag == "MemoRecord":
               # Fetch the referenced record from the database and return it.
               cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),))
               key, task = cursor.fetchone()
               return MemoRecord(key, task)
           else:
               # Always raises an error if you cannot return the correct object.
               # Otherwise, the unpickler will think None is the object referenced
               # by the persistent ID.
               raise pickle.UnpicklingError("unsupported persistent object")


   def main():
       import io
       import pprint

       # Initialize and populate our database.
       conn = sqlite3.connect(":memory:")
       cursor = conn.cursor()
       cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)")
       tasks = (
           'give food to fish',
           'prepare group meeting',
           'fight with a zebra',
           )
       for task in tasks:
           cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,))

       # Fetch the records to be pickled.
       cursor.execute("SELECT * FROM memos")
       memos = [MemoRecord(key, task) for key, task in cursor]
       # Save the records using our custom DBPickler.
       file = io.BytesIO()
       DBPickler(file).dump(memos)

       print("Pickled records:")
       pprint.pprint(memos)

       # Update a record, just for good measure.
       cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1")

       # Load the records from the pickle data stream.
       file.seek(0)
       memos = DBUnpickler(file, conn).load()

       print("Unpickled records:")
       pprint.pprint(memos)


   if __name__ == '__main__':
       main()


Tables de distribution
----------------------

Pour personnaliser la sérialisation d'une classe à un endroit
particulier sans affecter le reste du code, on peut créer un
sérialiseur avec une table de distribution spécifique.

The global dispatch table managed by the "copyreg" module is available
as "copyreg.dispatch_table".  Therefore, one may choose to use a
modified copy of "copyreg.dispatch_table" as a private dispatch table.

Par exemple, le code

   f = io.BytesIO()
   p = pickle.Pickler(f)
   p.dispatch_table = copyreg.dispatch_table.copy()
   p.dispatch_table[SomeClass] = reduce_SomeClass

crée une instance de la classe "pickle.Pickler" avec une table de
distribution propre qui traite la classe "SomeClass" de manière
spécifique. Le code

   class MyPickler(pickle.Pickler):
       dispatch_table = copyreg.dispatch_table.copy()
       dispatch_table[SomeClass] = reduce_SomeClass
   f = io.BytesIO()
   p = MyPickler(f)

does the same but all instances of "MyPickler" will by default share
the private dispatch table.  On the other hand, the code

   copyreg.pickle(SomeClass, reduce_SomeClass)
   f = io.BytesIO()
   p = pickle.Pickler(f)

modifies the global dispatch table shared by all users of the
"copyreg" module.


Traitement des objets à état
----------------------------

Here's an example that shows how to modify pickling behavior for a
class. The "TextReader" class below opens a text file, and returns the
line number and line contents each time its "readline()" method is
called. If a "TextReader" instance is pickled, all attributes *except*
the file object member are saved. When the instance is unpickled, the
file is reopened, and reading resumes from the last location. The
"__setstate__()" and "__getstate__()" methods are used to implement
this behavior.

   class TextReader:
       """Print and number lines in a text file."""

       def __init__(self, filename):
           self.filename = filename
           self.file = open(filename)
           self.lineno = 0

       def readline(self):
           self.lineno += 1
           line = self.file.readline()
           if not line:
               return None
           if line.endswith('\n'):
               line = line[:-1]
           return "%i: %s" % (self.lineno, line)

       def __getstate__(self):
           # Copy the object's state from self.__dict__ which contains
           # all our instance attributes. Always use the dict.copy()
           # method to avoid modifying the original state.
           state = self.__dict__.copy()
           # Remove the unpicklable entries.
           del state['file']
           return state

       def __setstate__(self, state):
           # Restore instance attributes (i.e., filename and lineno).
           self.__dict__.update(state)
           # Restore the previously opened file's state. To do so, we need to
           # reopen it and read from it until the line count is restored.
           file = open(self.filename)
           for _ in range(self.lineno):
               file.readline()
           # Finally, save the file.
           self.file = file

Voici un exemple d'utilisation :

   >>> reader = TextReader("hello.txt")
   >>> reader.readline()
   '1: Hello world!'
   >>> reader.readline()
   '2: I am line number two.'
   >>> new_reader = pickle.loads(pickle.dumps(reader))
   >>> new_reader.readline()
   '3: Goodbye!'


Réduction personnalisée pour les types, fonctions et autres objets
==================================================================

Ajouté dans la version 3.8.

Parfois, la simple utilisation de "dispatch_table" n'offre pas assez
de flexibilité. On peut vouloir changer la méthode de sérialisation
selon d'autres critères que le type de l'objet, ou bien personnaliser
la sérialisation des fonctions et des classes.

For those cases, it is possible to subclass from the "Pickler" class
and implement a "reducer_override()" method. This method can return an
arbitrary reduction tuple (see "__reduce__()"). It can alternatively
return "NotImplemented" to fallback to the traditional behavior.

Si "dispatch_table" et "reducer_override()" sont tous les deux
définis, "reducer_override()" a la priorité.

Note:

  Pour des raisons de performance, la méthode "reducer_override()"
  n'est jamais appelée sur "None", "True", "False", ainsi que les
  instances exactes (pas dérivées) de "int", "float", "bytes", "str",
  "dict", "set", "frozenset", "list" et "tuple".

Voici un exemple simple qui implémente la sérialisation d'une classe :

   import io
   import pickle

   class MyClass:
       my_attribute = 1

   class MyPickler(pickle.Pickler):
       def reducer_override(self, obj):
           """Custom reducer for MyClass."""
           if getattr(obj, "__name__", None) == "MyClass":
               return type, (obj.__name__, obj.__bases__,
                             {'my_attribute': obj.my_attribute})
           else:
               # For any other object, fallback to usual reduction
               return NotImplemented

   f = io.BytesIO()
   p = MyPickler(f)
   p.dump(MyClass)

   del MyClass

   unpickled_class = pickle.loads(f.getvalue())

   assert isinstance(unpickled_class, type)
   assert unpickled_class.__name__ == "MyClass"
   assert unpickled_class.my_attribute == 1


Tampons hors-bande
==================

Ajouté dans la version 3.8.

In some contexts, the "pickle" module is used to transfer massive
amounts of data.  Therefore, it can be important to minimize the
number of memory copies, to preserve performance and resource
consumption.  However, normal operation of the "pickle" module, as it
transforms a graph-like structure of objects into a sequential stream
of bytes, intrinsically involves copying data to and from the pickle
stream.

Cette contrainte peut être levée si le *producteur* (qui implémente
les types d'objets à transférer) et le *consommateur* (qui implémente
le système de communication) emploient les possibilités de transfert
hors-bande offertes par les protocoles 5 et suivants.


API des producteurs
-------------------

The large data objects to be pickled must implement a
"__reduce_ex__()" method specialized for protocol 5 and higher, which
returns a "PickleBuffer" instance (instead of e.g. a "bytes" object)
for any large data.

A "PickleBuffer" object *signals* that the underlying buffer is
eligible for out-of-band data transfer.  Those objects remain
compatible with normal usage of the "pickle" module.  However,
consumers can also opt-in to tell "pickle" that they will handle those
buffers by themselves.


API des consommateurs
---------------------

Un système de communication peut gérer de manière spécifique les
objets "PickleBuffer" générés lors de la sérialisation d'un réseau
d'objets.

Du côté de l'expéditeur, il faut passer le paramètre *buffer_callback*
à "Pickler" (ou à "dump()" ou "dumps()"). Le *buffer_callback* sera
appelé avec chaque "PickleBuffer" généré lors de la sérialisation du
réseau d'objets. Les tampons accumulés par le *buffer_callback* ne
verront pas leurs données copiées dans le flux sérialisé. Il leur sera
substitué un marqueur léger.

Du côté du receveur, il faut passer l'argument *buffers* à "Unpickler"
(ou "load()" ou bien "loads()"). *buffers* est un itérable des tampons
passés à *buffer_callback*. Il doit fournir les tampons dans le même
ordre que celui dans lequel ils ont été passés à *buffer_callback*.
Les tampons fournis constituent la source des données qu'attendent les
reconstructeurs des objets dont la sérialisation a abouti aux objets
"PickleBuffer".

Entre expéditeur et receveur, le système de communication peut
implémenter son propre mécanisme de transfert pour les tampons hors-
bande. Parmi les optimisations possibles se trouvent l'utilisation de
mémoire partagée et la compression spécifique au type de données.


Exemple
-------

Voici un exemple trivial où est implémentée une classe fille de
"bytearray" capable de sérialisation hors-bande :

   class ZeroCopyByteArray(bytearray):

       def __reduce_ex__(self, protocol):
           if protocol >= 5:
               return type(self)._reconstruct, (PickleBuffer(self),), None
           else:
               # PickleBuffer is forbidden with pickle protocols <= 4.
               return type(self)._reconstruct, (bytearray(self),)

       @classmethod
       def _reconstruct(cls, obj):
           with memoryview(obj) as m:
               # Get a handle over the original buffer object
               obj = m.obj
               if type(obj) is cls:
                   # Original buffer object is a ZeroCopyByteArray, return it
                   # as-is.
                   return obj
               else:
                   return cls(obj)

Lorsqu'il rencontre le bon type, le reconstructeur (la méthode de
classe "_reconstruct") renvoie directement le tampon original. Il
s'agit d'une manière simple de simuler l'absence de copie dans cet
exemple simpliste.

En tant que consommateur des objets, on peut les sérialiser de la
manière classique. La désérialisation conduit alors à une copie :

   b = ZeroCopyByteArray(b"abc")
   data = pickle.dumps(b, protocol=5)
   new_b = pickle.loads(data)
   print(b == new_b)  # True
   print(b is new_b)  # False: a copy was made

Mais en passant un *buffer_callback* et en donnant les tampons
accumulés au désérialiseur, il n'y a plus de copie :

   b = ZeroCopyByteArray(b"abc")
   buffers = []
   data = pickle.dumps(b, protocol=5, buffer_callback=buffers.append)
   new_b = pickle.loads(data, buffers=buffers)
   print(b == new_b)  # True
   print(b is new_b)  # True: no copy was made

Cet exemple est limité par le fait que "bytearray" effectue sa propre
allocation de mémoire. Il n'est pas possible de créer un "bytearray"
sur la mémoire d'un autre objet. Cependant, certains types de données
que l'on trouve dans des bibliothèques externes, comme les tableaux
NumPy, n'ont pas cette limitation. Le passage hors-bande permet alors
de n'effectuer aucune copie (ou bien de minimiser le nombre de copies)
lors du transfert de données d'un système à l'autre ou d'un processus
à l'autre.

Voir aussi: **PEP 574** — Protocole *pickle* 5 avec données hors-bande


Restriction des noms dans l'espace de nommage global
====================================================

Par défaut, la désérialisation importe toutes les classes ou fonctions
que demande le flux de données. Dans bien des cas, ce comportement est
inacceptable, puisqu'il permet de faire exécuter du code arbitraire
dans l'environnement de désérialisation. Observez le résultat de ce
flux de données fait-main lorsqu'il est lu :

   >>> import pickle
   >>> pickle.loads(b"cos\nsystem\n(S'echo hello world'\ntR.")
   hello world
   0

Dans cet exemple, le désérialiseur importe la fonction "os.system()"
et l'applique à la chaîne de caractères ""echo hello world"". C'est
inoffensif, mais il n'est pas difficile d'imaginer des variantes qui
endommageraient le système.

C'est pour cette raison qu'il s'avère parfois nécessaire de contrôler
ce qui peut être désérialisé. Cela est possible en redéfinissant la
méthode "Unpickler.find_class()". Contrairement à ce que son nom
laisse penser, "Unpickler.find_class()" est appelée pour tous les noms
à chercher dans l'espace de nommage global, ce qui inclut les classes
mais aussi les fonctions. Par ce biais, il est possible d'interdire
complètement la résolution des noms globaux ou de la restreindre à un
sous-ensemble que l'on considère sûr.

Voici un exemple de désérialiseur qui permet seulement la
désérialisation d'un petit nombre de classes sûres du module
"builtins" :

   import builtins
   import io
   import pickle

   safe_builtins = {
       'range',
       'complex',
       'set',
       'frozenset',
       'slice',
   }

   class RestrictedUnpickler(pickle.Unpickler):

       def find_class(self, module, name):
           # Only allow safe classes from builtins.
           if module == "builtins" and name in safe_builtins:
               return getattr(builtins, name)
           # Forbid everything else.
           raise pickle.UnpicklingError("global '%s.%s' is forbidden" %
                                        (module, name))

   def restricted_loads(s):
       """Helper function analogous to pickle.loads()."""
       return RestrictedUnpickler(io.BytesIO(s)).load()

A sample usage of our unpickler working as intended:

   >>> restricted_loads(pickle.dumps([1, 2, range(15)]))
   [1, 2, range(0, 15)]
   >>> restricted_loads(b"cos\nsystem\n(S'echo hello world'\ntR.")
   Traceback (most recent call last):
     ...
   pickle.UnpicklingError: global 'os.system' is forbidden
   >>> restricted_loads(b'cbuiltins\neval\n'
   ...                  b'(S\'getattr(__import__("os"), "system")'
   ...                  b'("echo hello world")\'\ntR.')
   Traceback (most recent call last):
     ...
   pickle.UnpicklingError: global 'builtins.eval' is forbidden

Comme le montre l'exemple, il faut faire attention aux objets que l'on
autorise à être désérialisés. Si la sécurité est une priorité, il peut
être sage de se tourner vers des alternatives comme l'API du module
"xmlrpc.client", ou des bibliothèques tierces.


Performances
============

Recent versions of the pickle protocol (from protocol 2 and upwards)
feature efficient binary encodings for several common features and
built-in types. Also, the "pickle" module has a transparent optimizer
written in C.


Exemples
========

Dans les cas les plus simples, utilisez les fonctions "dump()" et
"load()".

   import pickle

   # An arbitrary collection of objects supported by pickle.
   data = {
       'a': [1, 2.0, 3+4j],
       'b': ("character string", b"byte string"),
       'c': {None, True, False}
   }

   with open('data.pickle', 'wb') as f:
       # Pickle the 'data' dictionary using the highest protocol available.
       pickle.dump(data, f, pickle.HIGHEST_PROTOCOL)

Le code suivant lit les données qui viennent d'être sérialisées

   import pickle

   with open('data.pickle', 'rb') as f:
       # The protocol version used is detected automatically, so we do not
       # have to specify it.
       data = pickle.load(f)


Command-line interface
======================

The "pickle" module can be invoked as a script from the command line,
it will display contents of the pickle files. However, when the pickle
file that you want to examine comes from an untrusted source, "-m
pickletools" is a safer option because it does not execute pickle
bytecode, see pickletools CLI usage.

   python -m pickle pickle_file [pickle_file ...]

The following option is accepted:

pickle_file

   A pickle file to read, or "-" to indicate reading from standard
   input.

Voir aussi:

  Module "copyreg"
     Enregistre les fonctions de sérialisation pour les types définis
     par l'utilisateur.

  Module "pickletools"
     Outils pour travailler sur les données sérialisées et les
     analyser.

  Module "shelve"
     Indexed databases of objects; uses "pickle".

  Module "copy"
     Copie superficielle ou récursive d'objets.

  Module "marshal"
     Sérialisation haute-performance des types natifs.

-[ Notes ]-

[1] À ne pas confondre avec ce que fait le module "marshal".

[2] C'est la raison pour laquelle les fonctions "lambda" ne peuvent
    pas être sérialisées : elles partagent toutes le même nom, à
    savoir "<lambda>".

[3] L'exception levée est généralement de type "ImportError" ou
    "AttributeError", mais ce n'est pas systématique.

[4] Le module "copy" fait appel à ce protocole pour les opérations de
    copie superficielle comme récursive.

[5] The limitation on alphanumeric characters is due to the fact that
    persistent IDs in protocol 0 are delimited by the newline
    character.  Therefore if any kind of newline characters occurs in
    persistent IDs, the resulting pickled data will become unreadable.
