2014-05-10 6 views
34

Io uso python 2.7 e sto provando a decapitare un oggetto. Mi chiedo quale sia la vera differenza tra i protocolli di sottaceto.Scelta del protocollo pickle Python?

import numpy as np 
import pickle 
class data(object): 
    def __init__(self): 
     self.a = np.zeros((100, 37000, 3), dtype=np.float32) 

d = data() 
print "data size: ", d.a.nbytes/1000000. 
print "highest protocol: ", pickle.HIGHEST_PROTOCOL 
pickle.dump(d,open("noProt", 'w')) 
pickle.dump(d,open("prot0", 'w'), protocol=0) 
pickle.dump(d,open("prot1", 'w'), protocol=1) 
pickle.dump(d,open("prot2", 'w'), protocol=2) 


out >> data size: 44.4 
out >> highest protocol: 2 

poi ho scoperto che i file salvati hanno dimensioni differenti su disco:

  • noProt: 177.6MB
  • prot0: 177.6MB
  • prot1: 44.4MB
  • prot2: 44.4 MB

So che prot0 è un file di testo leggibile, quindi non voglio usarlo. Suppongo che il protocollo 0 sia quello fornito di default.

Mi chiedo qual è la differenza tra i protocolli 1 e 2, c'è una ragione per cui dovrei scegliere l'uno o l'altro?

Qual è il migliore da usare, pickle o cPickle?

+13

"pick" sarebbe un buon sinonimo di "scelta" in questo titolo :) – chepner

+13

@chepner "Selezionando i puntatori del protocollo pickle python?" :) –

+5

@JonClements: ooh, sono * così * tentato di modificare il titolo ora! –

risposta

29

Dal pickle module data format documentation:

Al momento non ci sono 3 diversi protocolli che possono essere utilizzati per il decapaggio.

  • La versione di protocollo 0 è il protocollo ASCII originale ed è retrocompatibile con le versioni precedenti di Python.
  • Il protocollo versione 1 è il vecchio formato binario che è anche compatibile con le versioni precedenti di Python.
  • La versione di protocollo 2 è stata introdotta in Python 2.3. Fornisce un pickling molto più efficiente di classi di nuovo stile.

[...]

Se un protocollo non viene specificato, il protocollo viene utilizzato 0. Se il protocollo è specificato come valore negativo o HIGHEST_PROTOCOL, verrà utilizzata la versione di protocollo più alta disponibile.

Stick con la versione 2 del protocollo, soprattutto se si utilizza le classi personalizzate derivate da object (classi di nuovo stile). Il codice più moderno, in questi giorni.

A meno che non è necessario mantenere la compatibilità con le versioni precedenti di Python, è più facile attaccare solo con la versione più alto del protocollo è possibile mettere le mani su:

with open("prot2", 'wb') as pfile: 
    pickle.dump(d, pfile, protocol=pickle.HIGHEST_PROTOCOL) 

Poiché si tratta di un formato binario, assicurarsi di utilizzare 'wb' come modalità file!

cPickle e pickle sono in gran parte compatibili; le differenze si trovano nell'API offerta. Per la maggior parte dei casi d'uso, limitati a cPickle; è più veloce.Citando il nuovo documentation:

In primo luogo, cPickle possono essere fino a 1000 volte più veloce rispetto salamoia, perché il primo è implementato in C. In secondo luogo, nel modulo cPickle le callable Pickler() e Unpickler() sono funzioni e non classi. Ciò significa che non puoi usarli per derivare sottoclassi di decapaggio e sottotitoli personalizzati. La maggior parte delle applicazioni non ha bisogno di questa funzionalità e dovrebbe beneficiare delle prestazioni notevolmente migliorate del modulo cPickle.

+1

'pickle' è la versione C in Python 3 e Python 3.4 usa il protocollo 3 che è [due volte più veloce del protocollo 2] (http://stackoverflow.com/a/26860404/819417). –

+1

@CeesTimmerman: a patto che non [scriva singoli numeri interi] (http://stackoverflow.com/questions/24097507/why-pickle-version-4-is-slower-than-version-3) e quindi zoppichi il miglioramenti della velocità di framing, altrimenti è più lento. :-) Questa risposta è orientata verso Python 2, come questo è ciò che l'OP sta chiedendo. –

+0

Vedo e ho aggiunto il tag 'python-2.7'. Non è quel benchmark che mette a confronto 3 e 4 invece di 2 e 3? –

3

Per le persone che utilizzano Python 3, ci sono, come di Python 3.5, cinque possibili protocolli tra cui scegliere:

Attualmente ci sono 5 diversi protocolli che possono essere utilizzati per il decapaggio. Più alto è il protocollo utilizzato, il più recente, la versione di Python necessario per leggere la salamoia prodotta [doc]:

  • Protocol versione 0 è il protocollo originale “human-readable” ed è compatibile con i precedenti versioni di Python.

  • Il protocollo versione 1 è un vecchio formato binario che è anche compatibile con le versioni precedenti di Python.

  • La versione di protocollo 2 è stata introdotta in Python 2.3. Fornisce un pickling molto più efficiente di classi di nuovo stile. Fare riferimento a PEP 307 per informazioni su sui miglioramenti apportati dal protocollo 2.
  • Il protocollo versione 3 è stato aggiunto in Python 3.0. Ha il supporto esplicito per gli oggetti byte e non può essere annullato da Python 2.x. Questo è il protocollo predefinito e il protocollo raccomandato quando è richiesta la compatibilità con con altre versioni di Python 3.
  • La versione 4 del protocollo è stata aggiunta in Python 3.4. Aggiunge il supporto per oggetti molto grandi, il pickling di più tipi di oggetti e alcuni ottimizzazioni del formato di dati . Fare riferimento alla PEP 3154 Per informazioni su miglioramenti apportati dal protocollo 4.

Una regola generale è che si dovrebbe usare il più alto possibile che il protocollo è compatibile con ciò che si desidera utilizzare per. Quindi, se vuoi che sia retrocompatibile con Python 2, allora la versione 2 del protocollo è una buona scelta, se vuoi che sia retrocompatibile con tutte le versioni di Python, allora la versione 1 è buona. Se non ti interessa la compatibilità con le versioni precedenti, l'utilizzo di pickle.HIGHEST_PROTOCOL ti fornisce automaticamente il protocollo più alto per la tua versione di Python.

Anche in Python 3, l'importazione di pickle importa automaticamente l'implementazione C.

Un altro punto da notare in termini di compatibilità è che, per impostazione predefinita, i protocolli 3 e 4 utilizzano la codifica unicode delle stringhe mentre i protocolli precedenti no. Quindi in Python 3, se carichi un file in pickled che è stato messo in pickled in Python 2, probabilmente dovrai specificare esplicitamente la codifica per caricarlo correttamente.