Maison > développement back-end > Tutoriel Python > Sérialisation et désérialisation d'objets de la bibliothèque pickle intégrée de Python

Sérialisation et désérialisation d'objets de la bibliothèque pickle intégrée de Python

爱喝马黛茶的安东尼
Libérer: 2019-06-03 17:19:33
avant
2708 Les gens l'ont consulté

Nous souhaitons récemment archiver les résultats de téléchargement obtenus par le robot. Ce résultat est un objet Python (nous ne voulons pas simplement enregistrer un HTML ou un json, nous voulons réaliser l'intégralité du processus de téléchargement. réversible), j'ai donc pensé à utiliser la bibliothèque de cornichons intégrée de Python (bibliothèque de concombre mariné) pour sérialiser les objets en octets et les désérialiser si nécessaire.

Sérialisation et désérialisation dobjets de la bibliothèque pickle intégrée de Python

Vous pouvez simplement comprendre l'utilisation et la fonction de pickle grâce au code suivant.

In [2]: import pickle 
In [3]: class A:
        pass 
In [4]: a = A()
In [5]: a.foo = 'hello'
In [6]: a.bar = 2
In [7]: pick_ed = pickle.dumps(a) 
In [8]: pick_ed
Out[8]: b'\x80\x03c__main__\nA\nq\x00)\x81q\x01}q\x02(X\x03\x00\x00\x00fooq\x03X\x05\x00\x00\x00helloq\x04X\x03\x00\x00\x00barq\x05K\x02ub.'
In [9]: unpick = pickle.loads(pick_ed) 
In [10]: unpick
Out[10]: <__main__.A at 0x10ae67278>
In [11]: a
Out[11]: <__main__.A at 0x10ae67128>
In [12]: dir(unpick)
Out[12]:
[&#39;__class__&#39;,
&#39;__delattr__&#39;,
&#39;__dict__&#39;,
&#39;__dir__&#39;,
&#39;__doc__&#39;,
&#39;__eq__&#39;,
&#39;__format__&#39;,
&#39;__ge__&#39;,
&#39;__getattribute__&#39;,
&#39;__gt__&#39;,
&#39;__hash__&#39;,
&#39;__init__&#39;,
&#39;__init_subclass__&#39;,
&#39;__le__&#39;,
&#39;__lt__&#39;,
&#39;__module__&#39;,
&#39;__ne__&#39;,
&#39;__new__&#39;,
&#39;__reduce__&#39;,
&#39;__reduce_ex__&#39;,
&#39;__repr__&#39;,
&#39;__setattr__&#39;,
&#39;__sizeof__&#39;,
&#39;__slotnames__&#39;,
&#39;__str__&#39;,
&#39;__subclasshook__&#39;,
&#39;__weakref__&#39;,
&#39;bar&#39;,
&#39;foo&#39;]
In [13]: unpick.foo
Out[13]: &#39;hello&#39;
In [14]: unpick.bar
Out[14]: 2
Copier après la connexion

Vous pouvez voir que l'utilisation de pickle est quelque peu similaire à celle de json, mais il existe plusieurs différences fondamentales :

json est un format d'échange de données universel multilingue, généralement exprimé sous forme de texte, lisible par les humains. pickle est utilisé pour sérialiser des objets Python, uniquement pour Python. Le résultat de la sérialisation est des données binaires, qui ne sont pas lisibles par les humains. De plus, json ne peut sérialiser qu'une partie des types intégrés par défaut, et pickle peut sérialiser un grand nombre de données.

Il y a aussi un ancien maréchal également intégré. Mais cette bibliothèque est principalement destinée aux fichiers .pyc. Les types personnalisés ne sont pas pris en charge et ne sont pas complets. Par exemple, il ne peut pas gérer les applications cycliques. Si un objet fait référence à lui-même, l'interpréteur Python se bloquera lors de l'utilisation de marshal.

Problèmes de compatibilité des versions

Puisque pickle est pour Python, Python a différentes versions (et la différence entre 2 et 3 est très grande), il faut donc en tenir compte considération L'objet sérialisé peut-il être désérialisé par une version supérieure (ou inférieure ?) de Python.

Il existe actuellement 5 versions du protocole pickle. Plus la version est élevée, plus la version Python 0-2 est élevée pour Python2 et 3-4 pour Python3.

Protocol version 0 is the original “human-readable” protocol and is backwards compatible with earlier versions of 
Python.Protocol version 1 is an old binary format which is also compatible with earlier versions of Python.Protocol 
version 2 was introduced in Python 2.3. It provides much more efficient pickling of new-style classes. Refer to 
PEP 307for information about improvements brought by protocol 2. (从这个版本往后,性能有显著提高)Protocol version 3 
was added in Python 3.0. It has explicit support for bytes objects and cannot be unpickled by Python 2.x.This is the 
default protocol, and the recommended protocol when compatibility with other Python 3 versions is required.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. Refer to PEP 3154 for information about improvements brought byprotocol 4.
Copier après la connexion

La plupart des. les entrées des fonctions pickle (telles que dump(), dumps(), le constructeur Pickler) acceptent toutes un paramètre de version de protocole, qui a deux variables intégrées :

pickle.HIGHEST_PROTOCOL est actuellement 4

pickle. DEFAULT_PROTOCOL est actuellement 3

L'utilisation

est similaire à l'interface du module json intégré, dumps() est utilisé pour renvoyer les résultats de sérialisation, dump() est utilisé pour sérialiser puis écrire Importer le fichier. De la même manière, il existe Load() et Loads(). Parmi eux, vous pouvez spécifier la version du protocole lors de la sérialisation des dump(s). Cela n'est pas requis lors de la désérialisation et la version sera automatiquement identifiée. Ceci est très similaire à la commande zip.

Sérialisation des types intégrés

La plupart des types intégrés prennent en charge la sérialisation et la désérialisation. Ce qui nécessite une attention particulière, ce sont les fonctions. La sérialisation d'une fonction se base uniquement sur son nom et le module dans lequel elle se trouve. Ni le code de la fonction ni ses attributs (les fonctions de Python sont des objets de première classe et peuvent avoir des attributs) ne seront sérialisés. Cela nécessite que le module dans lequel se trouve la fonction soit importable dans l'environnement unpickle, sinon ImportError ou AttributeError se produira.

Il y a quelque chose d'intéressant ici : toutes les fonctions lambda ne sont pas Pickleable. Parce que leurs noms s'appellent .

Sérialisation des types personnalisés

Comme le code expérimental au début de cet article, dans la plupart des cas aucune opération supplémentaire ne peut réaliser l'opération de sérialisation/désérialisation . A noter que lors du processus de désérialisation, le __init__() de la classe n'est pas appelé pour initialiser un objet, mais une nouvelle instance non initialisée est créée puis ses attributs sont restaurés (très astucieux). Le pseudocode est le suivant :

def save(obj):
    return (obj.__class__, obj.__dict__) 
def load(cls, attributes):
    obj = cls.__new__(cls)
    obj.__dict__.update(attributes)
    return obj
Copier après la connexion

Si vous souhaitez effectuer certaines opérations supplémentaires pendant le processus de sérialisation, comme sauvegarder l'état de l'objet, vous pouvez utiliser les méthodes magiques du protocole pickle, les plus courantes sont __setstate__() et __getstate__( ).

Problèmes de sécurité (!)

Le début de la documentation de pickle dit : Ne dépicklez jamais un binaire provenant d'une source inconnue. Considérez le code suivant :

>>> import pickle
>>> pickle.loads(b"cos\nsystem\n(S&#39;echo hello world&#39;\ntR.")
hello world
0
Copier après la connexion

Une fois décoché, ce code importe os.system() puis appelle echo. Il n'y a aucun effet secondaire. Mais que se passe-t-il si c'est rm -rf /· ?

La suggestion donnée par le document est d'implémenter la logique de vérification dans Unpickler.find_class(). Les méthodes de fonction doivent être appelées lorsque des variables globales sont requises.

import builtins
import io
import pickle
 
safe_builtins = {
    &#39;range&#39;,
    &#39;complex&#39;,
    &#39;set&#39;,
    &#39;frozenset&#39;,
    &#39;slice&#39;,
}
 
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 &#39;%s.%s&#39; is forbidden" %
                                     (module, name))
 
def restricted_loads(s):
    """Helper function analogous to pickle.loads()."""
    return RestrictedUnpickler(io.BytesIO(s)).load()
Copier après la connexion

Compression

Il ne se compressera pas automatiquement après le décapage. Je pense que ce design est très bon. Il est découplé. . Les choses, la compression est laissée aux autres bibliothèques. Et vous pouvez également constater que même si le fichier après décapage est illisible, le contenu est toujours présenté en code ASCII et n'est pas tronqué. Vous devez appeler compress de la bibliothèque de compression. Après compression réelle, le volume est d'environ 1/3 du précédent, ce qui est très impressionnant.

Résumé

Il est un peu difficile de garder des variables globales importables. La question à laquelle je dois faire face est la suivante : si je dois ouvrir les choses que j'ai marinées aujourd'hui à l'avenir, puis-je toujours les ouvrir ?

Il existe plusieurs versions ici : la version du projet, la version python, la version du protocole pickle et les versions du package dont dépend le projet. Parmi eux, je pense que la version python et la version pickle peuvent compter en toute sécurité sur leur rétrocompatibilité et sont faciles à résoudre. Principalement le projet et la version et les versions dépendantes. Si l'objet à récupérer est très complexe, alors il est probable que la sauvegarde de l'ancienne version ne soit pas compatible avec la nouvelle version. Une solution possible consiste à verrouiller complètement toutes les dépendances, par exemple en enregistrant leurs valeurs de hachage. Si vous souhaitez restaurer une certaine séquence binaire, restaurez les dépendances spécifiques et les validations spécifiques du projet à ce moment-là.

Mais pour l'instant, notre exigence est essentiellement de décaper un objet request.Response. Je pense que nous pouvons compter sur leur rétrocompatibilité. Si un jour il y a un changement radical dans les requêtes, alors même si notre cornichon est compatible, le code ne sera pas compatible. À ce moment-là, d'autres stratégies peuvent être envisagées.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:kawabangga.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal