2015-01-29 25 views
69

Ich frage mich, ob es eine Möglichkeit gibt, ein Objekt zu laden, das in Python 2.4 mit Python 3.4 gebeizt wurde.Python 2-Objekt mit Python 3 entpacken

Ich habe 2to3 auf einer großen Menge von Unternehmens-Legacy-Code ausgeführt, um es auf den neuesten Stand zu bringen.

dies getan hat, wenn die Datei ausgeführt wird ich die folgende Fehlermeldung erhalten:

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) 

am gebeizt Objekt im Rennen suchen, es ist ein dict in einem dict, str Schlüssel und Werte des Typs enthält.

Also meine Frage ist: Gibt es eine Möglichkeit, ein Objekt, ursprünglich in Python 2.4 gebeizt, mit Python 3.4 zu laden?

+0

Does Python 2.4 'json' Modul haben? Vielleicht könnten Sie ein 2.4-Skript schreiben, das das Objekt entknickt und es als json-Objekt speichert, und dann ein 3.4-Skript schreiben, das das json-Objekt liest und als 3.4-kompatibles Pickle-Objekt speichert. Dies wäre eine einmalige Operation, die Sie auf all Ihren Pickle-Dateien ausführen. – Kevin

+0

Ich dachte in ähnlicher Weise, wenn ich bedenke, dass dies dicts sind Ich denke, ich könnte sys.stdout nur in eine Datei ändern und ausdrucken, aber ich möchte sehen, ob ich sie zuerst laden kann – Scironic

Antwort

110

Sie müssen pickle.load() mitteilen, wie Python-Bytezeichenfolgedaten in Python 3-Zeichenfolgen konvertiert werden, oder Sie können pickle anweisen, sie als Bytes zu belassen.

Standardmäßig werden alle Zeichenfolgendaten als ASCII dekodiert und die Decodierung schlägt fehl. Siehe 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.

Einstellen der Codierung latin1 können Sie die Daten direkt importieren:

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

aber Sie werden feststellen, dass keine Ihrer Strings überprüfen müssen verwenden den falschen Codec decodiert; Latin-1 funktioniert für jede Eingabe, da es die Bytewerte 0-255 direkt den ersten 256 Unicode-Codepunkten zuordnet.

Die Alternative wäre, die Daten mit encoding='bytes' zu laden und danach alle bytes Schlüssel und Werte zu decodieren.

+1

Wie könnte dies rückwärts kompatibel gemacht werden Python 2? Anscheinend ist das Kodierungsargument für Python 2 nicht vorhanden. – EpicAdv

+1

@EpicAdv: Sie müssen diesen Code nicht mit Python 2 kompatibel machen; Bei dieser Frage geht es darum, Python 2 Pickles in Python 3 zu laden. Für Python 2 das Schlüsselwort "encoding" löschen. –

+6

@EpicAdv: Sie können ein pickle_options Dictionary erstellen, das für python 2 leer ist oder "encoding" hat: ' latin1'' und sende \ * \ * pickle_options zum Beizen. So sollte es in beiden Versionen laufen. – pipefish

0

Die Verwendung von encoding = 'latin1' verursacht einige Probleme, wenn Ihr Objekt numpy Arrays enthält.

Verwendung von encoding = Bytes wird besser sein.

Bitte sehen diese answer