2009-03-30 15 views
9

Le module de décapage semble utiliser des caractères d'échappement de chaîne lors du décapage; cela devient inefficace, par ex. sur des tableaux numpy. Considérez ce qui suitManière plus efficace de décaper une chaîne

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

Les longueurs sont 1133 caractères et 4249 caractères respectivement. Z.dumps() révèle quelque chose comme "\ x00 \ x00" (zéros réels dans la chaîne), mais pickle semble utiliser la fonction repr() de la chaîne, ce qui donne "'\ x00 \ x00'" (zéros étant zéros ascii).

ie ("0" dans z.dumps() == False) et ("0" dans cPickle.dumps (z.dumps()) == true)

+0

Vous devez ajouter une question spécifique à votre message ré. –

+0

Que voulez-vous sérialiser une chaîne Python ou un tableau d'octets? – jfs

+1

doit être len (cPickle.dumps (z)) – vartec

Répondre

23

Essayez d'utiliser une version ultérieure du protocole pickle avec le paramètre de protocole à pickle.dumps(). La valeur par défaut est 0 et est un format de texte ASCII. Unes supérieur à 1 (je vous suggère d'utiliser pickle.HIGHEST_PROTOCOL). Les formats de protocole 1 et 2 (et 3 mais pour py3k) sont binaires et devraient être plus conservateurs.

+0

[Python 3 utilise le protocole 3 par défaut.] (Https://docs.python.org/3/library/pickle.html#data-stream-format) –

8

Solution:

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

quelque chose de plus sur le sujet: http://tinyurl.com/3ymhaj5. Fondamentalement, si vous numérotez sur disque, vous pouvez simplement faire gzip.open() au lieu d'ouvrir. –

+0

@ slack3r ce lien est mort. – kynan

+0

Le codec 'ascii' ne peut pas encoder le caractère 'xda' en position 1: ordinal pas dans la plage (128) –

1

Une amélioration de la réponse de VarTec, qui semble un peu plus efficace de la mémoire (car il ne force pas tout en une chaîne):

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) Ne pas coder les numéros de protocole, utiliser '-1' ou' HIGHEST_PROTOCOL' . (2) La compression subséquente est un ADD-ON et n'est pas pertinente à sa question. (3) Spécifier 'compresslevel' quand la décompression est inutile; toute information qui pourrait être nécessaire pour décompresser le fichier serait stockée dans l'en-tête du fichier compressé - sinon comment seriez-vous capable de décompresser un fichier si vous ne saviez pas quel niveau de compression était utilisé? –

+0

(1) Alors le code py2 ne lira pas les objets py3. (2) l'en-tête dit "une amélioration de la réponse de vartec", qui utilisait la compression - je pense qu'elle utilisait moins de mem, mais cela aurait pu être une fausse impression ... (3) corrigé – gatoatigrado

3

z.dumps() est déjà décaper chaîne c'est-à-dire, il peut être décoché en utilisant pickle.loads():

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