2015-01-29 2 views
69

Мне интересно, есть ли способ загрузить объект, который был маринован в Python 2.4, с Python 3.4.Unpickling python 2 object with python 3

Я использую 2to3 на большом количестве устаревшего кода компании, чтобы обновить его.

Сделав это, при запуске файла я получаю следующее сообщение об ошибке:

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) 

глядя на квашеный объекте в ссоре, это в dictdict, содержащие ключи и значение типа str.

Итак, мой вопрос: есть ли способ загрузить объект, первоначально замаринованный в python 2.4, с помощью python 3.4?

+0

ли Python 2.4 есть 'json' модуль? Возможно, вы могли бы написать сценарий 2.4, который разглаживает объект и сохраняет его как объект json, а затем записывает скрипт 3.4, который читает объект json и сохраняет его как 3.4-совместимый объект рассола. Это будет одноразовая операция, которую вы запускаете на всех ваших файлах pickle. – Kevin

+0

Я думал о похожих строках, учитывая, что это dicts, я считаю, что могу просто сменить sys.stdout на файл и распечатать его, но я хочу посмотреть, могу ли я загрузить их сначала – Scironic

ответ

110

Вы должны указать pickle.load(), как преобразовать данные Python в строки Python 3, или вы можете сообщить pickle, чтобы оставить их в виде байтов.

По умолчанию необходимо попробовать и декодировать все строковые данные как ASCII, и это декодирование завершается с ошибкой. Смотрите 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.

Настройка кодировки для latin1 позволяет импортировать данные непосредственно:

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

но вам нужно, чтобы убедиться, что ни один из ваших строк декодируются с помощью неправильный кодек; Latin-1 работает для любого ввода, поскольку он отображает байтовые значения 0-255 на первые 256 кодов Unicode напрямую.

Альтернативой является загрузка данных с помощью encoding='bytes' и последующее декодирование всех bytes ключей и значений.

+1

Как это можно сделать обратно совместимым с Python 2? По-видимому, аргумент кодирования отсутствует для Python 2. – EpicAdv

+1

@EpicAdv: вам не нужно делать этот код совместимым с Python 2; этот вопрос касается того, как загрузить пинтон Python 2 в Python 3. Отсоедините ключевое слово 'encoding' для Python 2. –

+6

@EpicAdv: вы можете создать словарь pickle_options, который либо пуст для python 2, либо имеет' 'encoding ':' latin1'' и отправить \ * \ * pickle_options на рассол. Таким образом, он должен работать в обеих версиях. – pipefish

0

Использование encoding = 'latin1' вызывает некоторые проблемы, когда ваш объект содержит в нем массивы numpy.

Использование кодирования = байт будет лучше.

Пожалуйста, смотрите этот answer