2009-03-30 17 views
9

Il modulo pickle sembra utilizzare i caratteri di escape della stringa durante il decapaggio; questo diventa inefficiente per es. su array numpy. Considerare le seguentiun modo più efficiente di mettere sotto aceto una stringa

z = numpy.zeros(1000, numpy.uint8) 
len(z.dumps()) 
len(cPickle.dumps(z.dumps())) 

Le lunghezze sono rispettivamente 1133 e 4249 caratteri caratteri.

z.dumps() rivela qualcosa come "\ x00 \ x00" (zeri effettivi in ​​stringa), ma pickle sembra utilizzare la funzione repr() della stringa, restituendo "'\ x00 \ x00'" (essendo gli zeri ascii zeri).

cioè ("0" in z.dumps() == false) e ("0" in cPickle.dumps (z.dumps()) == true)

+0

È necessario aggiungere una domanda specifica al proprio post ri. –

+0

Cosa vuoi serializzare una stringa Python o una serie numerica di byte? – jfs

+1

dovrebbe essere len (cPickle.dumps (z)) – vartec

risposta

23

provare a utilizzare una versione successiva del protocollo pickle con il parametro protocollo su pickle.dumps(). Il valore predefinito è 0 ed è un formato di testo ASCII. Quelli superiori a 1 (ti suggerisco di usare pickle.HIGHEST_PROTOCOL). I formati di protocollo 1 e 2 (e 3 ma questo è per py3k) sono binari e dovrebbero essere più conservativi dello spazio.

+0

[Python 3 utilizza il protocollo 3 per impostazione predefinita.] (Https://docs.python.org/3/library/pickle.html#data-stream-format) –

8

Soluzione:

import zlib, cPickle 

def zdumps(obj): 
    return zlib.compress(cPickle.dumps(obj,cPickle.HIGHEST_PROTOCOL),9) 

def zloads(zstr): 
    return cPickle.loads(zlib.decompress(zstr)) 

>>> len(zdumps(z)) 
128 
+0

Ecco qualcosa di più sull'argomento: http://tinyurl.com/3ymhaj5. Fondamentalmente, se stai serializzando su disco puoi semplicemente fare gzip.open() invece di aprire. –

+0

@ slack3r quel link è morto. – kynan

+0

Il codec 'ascii' non può codificare il carattere u '\ xda' in posizione 1: ordinale non compreso nell'intervallo (128) –

1

Un miglioramento alla risposta di Vartec, che sembra un po 'più efficiente della memoria (dal momento che non forza tutto in una stringa):

def pickle(fname, obj): 
    import cPickle, gzip 
    cPickle.dump(obj=obj, file=gzip.open(fname, "wb", compresslevel=3), protocol=2) 

def unpickle(fname): 
    import cPickle, gzip 
    return cPickle.load(gzip.open(fname, "rb")) 
+0

-1 (1) Non utilizzare i numeri di protocollo hard-code, usare '-1' o' HIGHEST_PROTOCOL'. . (2) La compressione successiva è un ADD-ON ed è irrilevante alla sua domanda. (3) Specificare 'compresslevel' quando la decompressione non ha senso; qualsiasi informazione che potrebbe essere necessaria per decomprimere il file verrebbe archiviata nell'intestazione del file compresso, altrimenti come si sarebbe in grado di decomprimere un file se non si conoscesse il livello di compressione utilizzato? –

+0

(1) Quindi il codice py2 non leggerà gli oggetti py3. (2) l'intestazione dice "un miglioramento della risposta di vartec", che stava usando la compressione - penso che abbia usato meno mem, ma potrebbe essere stata una falsa impressione ... (3) risolta – gatoatigrado

3

z.dumps() è già in salamoia stringa cioè, può essere deselezionato utilizzando pickle.loads():

>>> z = numpy.zeros(1000, numpy.uint8) 
>>> s = z.dumps() 
>>> a = pickle.loads(s) 
>>> all(a == z) 
True