Pickle ou json?

114

Eu preciso para salvar no disco um pouco dictobjeto cujas chaves são do tipo stre os valores são ints e depois recuperá-lo . Algo assim:

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

Qual é a melhor opção e por quê? Serializar com pickleou com simplejson?

Estou usando o Python 2.6.

Juanjo Conti
fonte
convertê-lo em quê? Além disso, em que sentido melhor ?
SilentGhost
10
No 2.6 você não usaria simplejson, usaria o jsonmódulo embutido (que tem exatamente a mesma interface).
Mike Graham
5
"melhor"? Melhor para quê? Rapidez? Complexidade? Flexibilidade? Custo?
S.Lott
@Trilarion: YAML é um superconjunto de JSON
Martin Thoma

Respostas:

68

Se você não tem nenhum requisito de interoperabilidade (por exemplo, você vai apenas usar os dados com Python) e um formato binário está bom, vá com cPickle que fornece serialização de objetos Python muito rápida.

Se você deseja interoperabilidade ou um formato de texto para armazenar seus dados, use JSON (ou algum outro formato apropriado, dependendo de suas restrições).

Håvard S
fonte
48
JSON parece ser mais rápido do que cPickle.
mac
5
Minha resposta destaca as preocupações que considero mais importantes a serem consideradas ao escolher qualquer uma das soluções. Eu não afirmo sobre ser mais rápido do que o outro. Se JSON for mais rápido E adequado de outra forma, vá com JSON! (
Håvard S
10
My point is: there is no real reason for using cPickle (or pickle) based on your premises over JSON. When I first read your answer I thought the reason might have been speed, but since this is not the case... :)
mac
14
O benchmark citado por @mac testa apenas strings. Eu testei str, int e float separadamente e descobri que json é mais lento que cPickle com serialização de float, mas mais rápido com desserialização de float. Para int (e str), json é mais rápido em ambos os sentidos. Dados e código: gist.github.com/marians/f1314446b8bf4d34e782
Marian
24
O protocolo mais recente do cPickle agora é mais rápido do que JSON. O comentário votado sobre JSON ser mais rápido está desatualizado em alguns anos. stackoverflow.com/a/39607169/1007353
JDiMatteo
104

Eu prefiro JSON em vez de pickle para minha serialização. O Unpickling pode executar código arbitrário e usar picklepara transferir dados entre programas ou armazenar dados entre sessões é uma falha de segurança. JSON não apresenta uma falha de segurança e é padronizado, portanto, os dados podem ser acessados ​​por programas em diferentes linguagens se você precisar.

Mike Graham
fonte
Obrigado. De qualquer forma, estarei despejando e carregando no mesmo programa.
Juanjo Conti
2
Embora os riscos de segurança possam ser baixos em seu aplicativo atual, o JSON permite que você feche o todo.
Mike Graham
4
One can create a pickle-virus that pickles itself into everything that is pickled after loaded. With json this is not possible.
User
2
Além da segurança, o JSON tem a vantagem adicional de facilitar as migrações, para que você possa carregar dados salvos por uma versão mais antiga do seu aplicativo. Enquanto isso, você poderia ter adicionado um campo ou substituído uma subestrutura inteira. Escrever tal conversor (migração) para dict / list é simples, mas com o Pickle você terá dificuldade em carregá-lo em primeiro lugar, antes mesmo de pensar em converter.
vog
2
Eu não tinha pensado sobre esse aspecto (segurança e a capacidade de objetos em conserva rodarem código arbitrário). Obrigado por apontar isso!
CaffeinatedMike
20

Se você está preocupado principalmente com velocidade e espaço, use cPickle porque cPickle é mais rápido que JSON.

Se você está mais preocupado com interoperabilidade, segurança e / ou legibilidade humana, use JSON.


Os resultados dos testes referenciados em outras respostas foram registrados em 2010, e os testes atualizados em 2016 com protocolo cPickle 2 mostram:

  • Carregamento cPickle 3,8x mais rápido
  • cPickle 1.5x mais rápido
  • Codificação cPickle ligeiramente menor

Reproduza você mesmo com esta essência , que é baseada no benchmark de Konstantin referenciado em outras respostas, mas usando cPickle com protocolo 2 em vez de pickle, e usando json em vez de simplejson (já que json é mais rápido que simplejson ), por exemplo,

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

Resultados com o python 2.7 em um processador Xeon 2015 decente:

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 com protocolo pickle 3 é ainda mais rápido.

JDiMatteo
fonte
11

JSON ou picles? Que tal JSON e pickle! Você pode usar jsonpickle. É fácil de usar e o arquivo no disco é legível porque é JSON.

http://jsonpickle.github.com/

Paul Hildebrandt
fonte
2
Alguém fez o benchmarking de seu desempenho em relação às opções? É comparável em desempenho como json bruto como visto aqui benfrederickson.com/dont-pickle-your-data ?
Josep Valls
Este não é um benchmark abrangente, mas eu tinha um jogo onde salvava os níveis usando pickle (python3). Eu queria tentar jsonpickle para o aspecto legível por humanos - no entanto, os salvamentos de nível eram tristemente muito mais lentos. 1597ms para jsonpickle e 88ms ou pickle regular no nível de salvamento. Para carga nivelada, 1604ms para jsonpickle e 388 para pickle. Pena que eu gosto dos arquivos salvos legíveis por humanos.
Neil McGill
Eu testei isso em nosso sistema de comércio, a legibilidade vem com cerca de 2x serialização + penalidade de velocidade de desserialização em comparação com pickle. Ótimo para qualquer outra coisa, no entanto.
nurettin
6

Eu tentei vários métodos e descobri que usar cPickle com a configuração do argumento de protocolo do método de despejo como: cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)é o método de despejo mais rápido.

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)

Resultado:

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

Pessoalmente, geralmente prefiro JSON porque os dados são legíveis por humanos . Definitivamente, se você precisar serializar algo que JSON não aceita, use pickle.

Mas para a maioria do armazenamento de dados, você não precisa serializar nada estranho e JSON é muito mais fácil e sempre permite que você o abra em um editor de texto e verifique os dados você mesmo.

A velocidade é boa, mas para a maioria dos conjuntos de dados a diferença é insignificante; Python geralmente não é muito rápido de qualquer maneira.

rickcnagy
fonte
1
Verdade. Mas, para os 100elementos de uma lista, a diferença é completamente desprezível ao olho humano. Definitivamente diferente ao trabalhar com conjuntos de dados maiores.
rickcnagy