2015-01-29 15 views
69

Mi chiedo se c'è un modo per caricare un oggetto che è stato decapitato in Python 2.4, con Python 3.4.Unpickling di un oggetto python 2 con python 3

Ho eseguito 2to3 su una grande quantità di codice legacy aziendale per aggiornarlo.

Dopo aver fatto questo, quando si esegue il file ottengo il seguente errore:

File "H:\fixers - 3.4\addressfixer - 3.4\trunk\lib\address\address_generic.py" 
, line 382, in read_ref_files 
    d = pickle.load(open(mshelffile, 'rb')) 
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 1: ordinal 
not in range(128) 

guardare l'oggetto in salamoia in lizza, è un dict in un dict, contenente chiavi e valori di tipo str.

Quindi la mia domanda è: c'è un modo per caricare un oggetto, originariamente decapitato in python 2.4, con python 3.4?

+0

fa Python 2.4 hanno il modulo 'json'? Forse potresti scrivere uno script 2.4 che despassa l'oggetto e lo salva come un oggetto json, e poi scrivi uno script 3.4 che legge l'oggetto json e lo salva come oggetto pickle compatibile con 3.4. Questa operazione potrebbe essere eseguita una volta sola su tutti i file pickle. – Kevin

+0

Stavo pensando in modo simile, considerando che si tratta di dts, penso che potrei semplicemente cambiare sys.stdout in un file e stamparli, ma voglio vedere se riesco a caricarli prima – Scironic

risposta

110

Dovrete comunicare a pickle.load() come convertire Python tramite l'attribuzione di dati a stringhe di Python 3 oppure è possibile indicare a pickle di lasciarli come byte.

L'impostazione predefinita è di provare e decodificare tutti i dati di stringa come ASCII e quella decodifica non riesce. Vedere la pickle.load() documentation:

Optional keyword arguments are fix_imports, encoding and errors, which are used to control compatibility support for pickle stream generated by Python 2. If fix_imports is true, pickle will try to map the old Python 2 names to the new names used in Python 3. The encoding and errors tell pickle how to decode 8-bit string instances pickled by Python 2; these default to ‘ASCII’ and ‘strict’, respectively. The encoding can be ‘bytes’ to read these 8-bit string instances as bytes objects.

impostare la codifica a latin1 permette di importare i dati direttamente:

with open(mshelffile, 'rb') as f: 
    d = pickle.load(f, encoding='latin1') 

ma è necessario verificare che nessuna delle corde vengono decodificati utilizzando il codec sbagliato; Latin-1 funziona per qualsiasi input mentre esegue il mapping dei valori di byte da 0-255 ai primi 256 codepoint Unicode direttamente.

L'alternativa sarebbe caricare i dati con encoding='bytes' e decodificare tutte le chiavi e i valori bytes in seguito.

+1

Come potrebbe essere reso compatibile con le versioni precedenti Python 2? Apparentemente, l'argomento di codifica non è presente per Python 2. – EpicAdv

+1

@EpicAdv: non è necessario rendere questo codice compatibile con Python 2; questa domanda riguarda come caricare Python 2 pickles in Python 3. Eliminare completamente la parola chiave 'encoding' per Python 2. –

+6

@EpicAdv: è possibile creare un dizionario pickle_options vuoto per python 2 o con' 'encoding': ' latin1'' e invia \ * \ * pickle_options a pickle. In questo modo dovrebbe essere eseguito in entrambe le versioni. – pipefish

0

L'uso di encoding = 'latin1' provoca alcuni problemi quando l'oggetto contiene matrici numpy.

L'utilizzo della codifica = byte sarà migliore.

Si prega di vedere questo answer