2014-04-03 11 views
5

ho salamoia dati da 2,7 che ho in salamoia come questo:dati deserializzazione da Python 2 con stringhe Unicode in Python 3

#!/usr/bin/env python2 
# coding=utf-8 

import pickle 

data = {1: datetime.date(2014, 3, 18), 
     'string-key': u'ünicode-string'} 

pickle.dump(data, open('file.pickle', 'wb')) 

L'unico modo che ho trovato per caricare questo in Python 3.4 è:

data = pickle.load(open('file.pickle', "rb"), encoding='bytes') 

Ora la mia stringa unicode va bene ma i tasti dict sono bytes. print(repr(data)) dà:

{1: datetime.date(2014, 3, 18), b'string-key': 'ünicode-string'} 

Qualcuno ha un'idea per aggirare riscrivere il mio codice come data[b'string-key'] resp. convertire tutti i file esistenti?

+0

Non è previsto che i dati sottoposti a picking funzionino su versioni e implementazioni ed è un metodo di serializzazione piuttosto scadente da utilizzare anche quando funziona a tutti i costi poiché esegue codice arbitrario. Hai preso in considerazione l'utilizzo di JSON, invece? – geoffspear

+0

Ho una struttura più complessa che contiene dicts, tuple e tuple di tuple come valori e ho bisogno di confrontare le versioni dei dati salvati e con questo scopo le tuple sono molto più convenienti delle liste. Ma non ci sono tuple in JSON (e non ci sono anche date?). – TNT

+0

@Wooble: [ma in generale pickle dovrebbe sempre essere il modo preferito per serializzare oggetti Python] (https://docs.python.org/3/library/pickle.html#comparison-with-marshal) –

risposta

0

Dai un'occhiata all'implementazione.

È possibile creare una sottoclasse di Unpickler e sovrascrivere la deserializzazione dei byte per produrre stringhe.

4

Questa non è una risposta reale ma solo una soluzione alternativa. Questo converte i dati in salamoia alla versione 3 in Python 3.4 (non funziona in 3.3):

#!/usr/bin/env python3 

import pickle, glob 

def bytes_to_unicode(ob): 
    t = type(ob) 
    if t in (list, tuple): 
     l = [str(i, 'utf-8') if type(i) is bytes else i for i in ob] 
     l = [bytes_to_unicode(i) if type(i) in (list, tuple, dict) else i for i in l] 
     ro = tuple(l) if t is tuple else l 
    elif t is dict: 
     byte_keys = [i for i in ob if type(i) is bytes] 
     for bk in byte_keys: 
      v = ob[bk] 
      del(ob[bk]) 
      ob[str(bk,'utf-8')] = v 
     for k in ob: 
      if type(ob[k]) is bytes: 
       ob[k] = str(ob[k], 'utf-8') 
      elif type(ob[k]) in (list, tuple, dict): 
       ob[k] = bytes_to_unicode(ob[k]) 
     ro = ob 
    else: 
     ro = ob 
     print("unprocessed object: {0} {1}".format(t, ob)) 
    return ro 

for fn in glob.glob('*.pickle'): 

    data = pickle.load(open(fn, "rb"), encoding='bytes') 
    ndata = bytes_to_unicode(data) 
    pickle.dump(ndata, open(fn + '3', "wb")) 

Il Python docs dicono: formato di serializzazione

La salamoia è garantito per essere compatibile varie versioni di Python.

Non ho trovato un modo per pickle.load Python-2.7 dati in salamoia in Python 3.3 - nemmeno i dati che conteneva solo int s e date s.

+0

Dovresti aprire un bug (se non ne esiste già uno) sul [tracker dei bug di Python] (http://bugs.python.org). –

Problemi correlati