Unpickling объект python 2 с python 3

Мне интересно, есть ли способ загрузить объект, который был засолен в Python 2.4, с Python 3.4.

Я использовал 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)

Глядя на маринованном объекте в утверждении, его dict в dict, содержащий ключи и значение типа str.

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

Ответ 1

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

По умолчанию это попытка декодировать все строковые данные как ASCII, и это декодирование завершается неудачно. Смотрите документацию pickle.load():

Необязательными ключевыми аргументами являются fix_imports, encoding и errors, которые используются для управления поддержкой совместимости потока pickle, сгенерированного Python 2. Если fix_imports имеет значение true, pickle попытается отобразить старые имена Python 2 на новые имена, используемые в Python 3. кодирование и ошибки сообщают pickle, как декодировать экземпляры 8-битных строк, выбранные Python 2; по умолчанию это "ASCII" и "строгий" соответственно. Кодировка может быть байтовой для чтения этих 8-битных строковых экземпляров как байтовых объектов.

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

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

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

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

Обратите внимание, что вплоть до версий Python до 3.6.8, 3.7.2 и 3.8.0, извлечение данных объекта Python 2 datetime нарушается, если вы не используете encoding='bytes'.

Ответ 2

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

Использование encoding = bytes будет лучше.

Пожалуйста, смотрите этот ответ для полного объяснения использования encoding = bytes