Python: pourquoi cornichon?
J'ai utilisé pickle et j'étais très heureux, puis j'ai vu cet article: Ne pas décaper vos données
Lire plus loin, il semble que:
- le cornichon est lent
- le décapant est dangereux
- le cornichon n'est pas lisible par l'homme
- le cornichon n'est pas indépendant de la langue
Je suis passé à enregistrer mes données en tant que JSON, mais je voulais connaître les meilleures pratiques:
Compte tenu de tous ces problèmes, quand utiliseriez-vous pickle? Quel des situations spécifiques appellent à l'utiliser?
5 réponses
Pickle n'est pas sûr car il construit des objets Python arbitraires en invoquant des fonctions arbitraires. Cependant, cela lui donne également le pouvoir de sérialiser presque n'importe quel objet Python, sans aucune liste standard ou même blanche/noire (dans le cas commun). C'est très souhaitable pour certains cas d'utilisation:
- sérialisation rapide et facile, par exemple pour mettre en pause et reprendre un script simple mais de longue durée. Aucune des préoccupations n'a d'importance ici, vous voulez juste vider l'état du programme tel quel et de le charger plus tard.
- envoi de données Python arbitraires à d'autres processus ou ordinateurs, comme dans
multiprocessing
. Les problèmes de sécurité peuvent s'appliquer (mais surtout ne le font pas), la généralité est absolument nécessaire, et les humains n'auront pas à la lire.
Dans d'autres cas, aucun des inconvénients n'est suffisant pour justifier le travail de mappage de vos objets vers JSON ou un autre modèle de données restrictif. Peut-être que vous ne vous attendez pas à avoir besoin de lisibilité Humaine / Sécurité / compatibilité inter-langues ou peut-être que vous pouvez de faire sans. Rappelez-vous, vous N'en aurez pas besoin. L'utilisation de JSON serait la bonne chose™ mais right n'équivaut pas toujours à good.
Vous remarquerez que j'ai complètement ignoré l'inconvénient "lent". C'est parce que c'est partiellement trompeur: Pickle est en effet plus lent pour les données qui correspondent parfaitement au modèle JSON (chaînes, nombres, tableaux, cartes), mais si vos données sont comme ça, vous devriez utiliser JSON pour d'autres raisons. Si vos données ne sont pas comme ça (très probablement), vous devez également prendre en compte le code personnalisé vous aurez besoin de transformer vos objets en données JSON, et le code personnalisé vous aurez besoin de transformer les données JSON dans vos objets. Il ajoute à la fois l'effort d'ingénierie et les frais généraux d'exécution, qui doivent être quantifiés au cas par cas.
Pickle a l'avantage de la commodité - il peut sérialiser des graphiques d'objets arbitraires sans travail supplémentaire, et fonctionne sur une assez large gamme de types Python. Cela dit, il serait inhabituel pour moi d'utiliser Pickle dans le nouveau code. JSON est juste beaucoup plus propre à travailler avec.
Je n'utilise généralement ni Pickle, ni JSON, mais MessagePack Il est à la fois sûr et rapide, et produit des données sérialisées de petite taille.
Un avantage supplémentaire est la possibilité d'échanger des données avec un logiciel écrit dans d'autres langues (ce qui est bien sûr également vrai dans le cas de JSON).
Vous pouvez trouver une réponse sur JSON vs. Pickle security : JSON ne peut que pickle unicode, int, float, NoneType, bool, list et dict. Vous ne pouvez pas l'utiliser si vous voulez décaper des objets plus avancés tels que l'instance de classes. Notez que pour ces types de cornichons, il n'y a aucun espoir d'être agnostique de la langue.
En utilisant également cPickle
au lieu de Pickle
, résolvez partiellement la progression de la vitesse.
J'ai essayé plusieurs méthodes et j'ai découvert que l'utilisation de cPickle avec la définition de l'argument de protocole de la méthode dumps comme: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)
est la méthode de vidage la plus rapide.
import msgpack
import json
import pickle
import timeit
import cPickle
import numpy as np
num_tests = 10
obj = np.random.normal(0.5, 1, [240, 320, 3])
command = 'pickle.dumps(obj)'
setup = 'from __main__ import pickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("pickle: %f seconds" % result)
command = 'cPickle.dumps(obj)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle: %f seconds" % result)
command = 'cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle highest: %f seconds" % result)
command = 'json.dumps(obj.tolist())'
setup = 'from __main__ import json, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("json: %f seconds" % result)
command = 'msgpack.packb(obj.tolist())'
setup = 'from __main__ import msgpack, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("msgpack: %f seconds" % result)
Sortie:
pickle : 0.847938 seconds
cPickle : 0.810384 seconds
cPickle highest: 0.004283 seconds
json : 1.769215 seconds
msgpack : 0.270886 seconds
Donc, je préfère cPickle avec le protocole de dumping le plus élevé dans les situations qui nécessitent des performances en temps réel telles que le streaming vidéo d'une caméra à serveur.