Pickle ou json?

114

Je dois enregistrer sur le disque un petit dictobjet dont les clés sont du type stret les valeurs sont ints , puis le récupérer . Quelque chose comme ça:

{'juanjo': 2, 'pedro':99, 'other': 333}

Quelle est la meilleure option et pourquoi? Sérialisez-le avec pickleou avec simplejson?

J'utilise Python 2.6.

Juanjo Conti
la source
le convertir en quoi? Aussi, dans quel sens mieux ?
SilentGhost
10
Dans la version 2.6, vous n'utiliseriez pas simplejson, vous utiliseriez le jsonmodule intégré (qui a exactement la même interface).
Mike Graham
5
"meilleur"? Le mieux pour quoi? La vitesse? Complexité? La flexibilité? Coût?
S.Lott
@Trilarion: YAML est un sur-ensemble de JSON
Martin Thoma

Réponses:

68

Si vous n'avez pas d'exigences d'interopérabilité (par exemple, vous allez simplement utiliser les données avec Python) et qu'un format binaire convient, optez pour cPickle qui vous donne une sérialisation d'objets Python très rapide.

Si vous souhaitez une interopérabilité ou un format texte pour stocker vos données, optez pour JSON (ou un autre format approprié en fonction de vos contraintes).

Håvard S
la source
48
JSON semble être plus rapide que cPickle.
mac
5
Ma réponse met en évidence les préoccupations qui me semblent les plus importantes à prendre en compte lors du choix de l'une ou l'autre solution. Je ne prétends pas que l'un ou l'autre soit plus rapide que l'autre. Si JSON est plus rapide ET autrement adapté, optez pour JSON! (C'est-à-dire, il n'y a aucune raison pour votre vote défavorable.)
Håvard S
10
Mon point est le suivant: il n'y a pas de vraie raison d'utiliser cPickle(ou pickle) basé sur vos locaux sur JSON. Quand j'ai lu votre réponse pour la première fois, j'ai pensé que la raison en était peut-être la rapidité, mais comme ce n'est pas le cas ... :)
mac
14
Le benchmark cité par @mac ne teste que les chaînes. J'ai testé str, int et float séparément et j'ai découvert que json est plus lent que cPickle avec la sérialisation float, mais plus rapide avec la désérialisation float. Pour int (et str), json est plus rapide dans les deux sens. Données et code: gist.github.com/marians/f1314446b8bf4d34e782
Marian
24
Le dernier protocole de cPickle est désormais plus rapide que JSON. Le commentaire voté sur la rapidité de JSON est dépassé de quelques années. stackoverflow.com/a/39607169/1007353
JDiMatteo
104

Je préfère JSON à pickle pour ma sérialisation. Unpickling peut exécuter du code arbitraire, et l'utilisation picklepour transférer des données entre des programmes ou stocker des données entre des sessions est une faille de sécurité. JSON n'introduit pas de faille de sécurité et est standardisé, de sorte que les données peuvent être consultées par des programmes dans différentes langues si vous en avez besoin.

Mike Graham
la source
Merci. Quoi qu'il en soit, je vais vider et charger dans le même programme.
Juanjo Conti
2
Bien que les risques de sécurité puissent être faibles dans votre application actuelle, JSON vous permet de fermer complètement le tout.
Mike Graham
4
On peut créer un virus de cornichon qui se décortique dans tout ce qui est mariné après avoir été chargé. Avec json, ce n'est pas possible.
Utilisateur
2
Outre la sécurité, JSON présente l'avantage supplémentaire de faciliter les migrations, ce qui vous permet de charger des données qui ont été enregistrées par une ancienne version de votre application. En attendant, vous auriez pu ajouter un champ ou remplacer toute une sous-structure. Écrire un tel convertisseur (migration) pour dict / list est simple, mais avec Pickle, vous aurez du mal à le charger en premier lieu, avant même de pouvoir penser à convertir.
vog le
2
Je n'avais pas pensé à cet aspect (sécurité et possibilité pour les objets picklés d'exécuter du code arbitraire). Merci d'avoir fait remarquer cela!
CaffeinatedMike
20

Si vous êtes principalement préoccupé par la vitesse et l'espace, utilisez cPickle car cPickle est plus rapide que JSON.

Si vous êtes plus préoccupé par l'interopérabilité, la sécurité et / ou la lisibilité humaine, utilisez JSON.


Les résultats des tests référencés dans d'autres réponses ont été enregistrés en 2010, et les tests mis à jour en 2016 avec le protocole cPickle 2 montrent:

  • Chargement cPickle 3.8x plus rapide
  • Lecture cPickle 1.5x plus rapide
  • cPickle encodage légèrement plus petit

Reproduisez-le vous-même avec cet essentiel , qui est basé sur le benchmark de Konstantin référencé dans d'autres réponses, mais en utilisant cPickle avec le protocole 2 au lieu de pickle, et en utilisant json au lieu de simplejson (puisque json est plus rapide que simplejson ), par exemple

wget https://gist.github.com/jdimatteo/af317ef24ccf1b3fa91f4399902bb534/raw/03e8dbab11b5605bc572bc117c8ac34cfa959a70/pickle_vs_json.py
python pickle_vs_json.py

Résultats avec python 2.7 sur un processeur Xeon 2015 décent:

Dir Entries Method  Time    Length

dump    10  JSON    0.017   1484510
load    10  JSON    0.375   -
dump    10  Pickle  0.011   1428790
load    10  Pickle  0.098   -
dump    20  JSON    0.036   2969020
load    20  JSON    1.498   -
dump    20  Pickle  0.022   2857580
load    20  Pickle  0.394   -
dump    50  JSON    0.079   7422550
load    50  JSON    9.485   -
dump    50  Pickle  0.055   7143950
load    50  Pickle  2.518   -
dump    100 JSON    0.165   14845100
load    100 JSON    37.730  -
dump    100 Pickle  0.107   14287900
load    100 Pickle  9.907   -

Python 3.4 avec le protocole pickle 3 est encore plus rapide.

JDiMatteo
la source
11

JSON ou cornichon? Que diriez-vous de JSON et de cornichon! Vous pouvez utiliser jsonpickle. Il est facile à utiliser et le fichier sur le disque est lisible car il est JSON.

http://jsonpickle.github.com/

Paul Hildebrandt
la source
2
Quelqu'un a-t-il évalué ses performances par rapport aux options? Est-il comparable en performances au json brut comme on le voit ici benfrederickson.com/dont-pickle-your-data ?
Josep Valls
Ce n'est pas un benchmark large, mais j'avais un jeu existant où il sauvegardait les niveaux en utilisant pickle (python3). Je voulais essayer jsonpickle pour l'aspect lisible par l'homme - mais les sauvegardes de niveau étaient malheureusement beaucoup plus lentes. 1597ms pour jsonpickle et 88ms ou pickle régulier sur sauvegarde de niveau. Pour une charge de niveau, 1604 ms pour jsonpickle et 388 pour pickle. Dommage que j'aime les sauvegardes lisibles par l'homme.
Neil McGill
J'ai testé cela dans notre système de trading, la lisibilité est accompagnée d'environ 2x pénalité de vitesse de sérialisation + désérialisation par rapport à pickle. Idéal pour tout le reste, cependant.
nurettin le
6

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 de cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)vidage comme: 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)

Production:

pickle         :   0.847938 seconds
cPickle        :   0.810384 seconds
cPickle highest:   0.004283 seconds
json           :   1.769215 seconds
msgpack        :   0.270886 seconds
Ahmed Abobakr
la source
4

Personnellement, je préfère généralement JSON car les données sont lisibles par l'homme . Certainement, si vous avez besoin de sérialiser quelque chose que JSON ne prendra pas, utilisez pickle.

Mais pour la plupart du stockage de données, vous n'aurez pas besoin de sérialiser quoi que ce soit de bizarre et JSON est beaucoup plus facile et vous permet toujours de l'ouvrir dans un éditeur de texte et de vérifier les données vous-même.

La vitesse est bonne, mais pour la plupart des jeux de données, la différence est négligeable; De toute façon, Python n'est généralement pas trop rapide.

rickcnagy
la source
1
Vrai. Mais pour les 100éléments d'une liste, la différence est complètement négligeable à l'œil humain. Certainement différent lorsque vous travaillez avec des ensembles de données plus volumineux.
rickcnagy