Від'єднання об'єкта python 2 з python 3


129

Мені цікаво, чи існує спосіб завантаження об'єкта, який був вибраний в 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)

Дивлячись на маринований об’єкт із суперечкою, це dictin a dict, що містить ключі та значення типу str.

Отже, моє запитання: чи існує спосіб завантаження об'єкта, спочатку зібраного в python 2.4, з python 3.4?


1
Чи має jsonмодуль Python 2.4 ? Можливо, ви могли б написати сценарій 2.4, який видаляє об'єкт і зберігає його як json-об’єкт, а потім написати 3.4-скрипт, який читає json-об’єкт і зберігає його як 3.4-сумісний об’єкт маринування. Це була б разова операція, яку ви виконуєте на всіх ваших файлах підбору.
Кевін

Я роздумував над подібними рядками, вважаючи, що це дикти, я вважаю, що я міг просто змінити sys.stdout у файл та роздрукувати їх, але я хочу побачити, чи можу я їх завантажити спочатку
NDevox

Питання, пов’язані з датами, зокрема: stackoverflow.com/questions/24805105/…
Джон Y

Відповіді:


189

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

За замовчуванням - спробувати розшифрувати всі рядкові дані як ASCII, і це декодування не вдалося. Дивіться pickle.load()документацію :

Додатковими аргументами ключових слів є fix_imports , кодування та помилки , які використовуються для управління підтримкою сумісності потоку маринованих сигналів, згенерованого Python 2. Якщо true_imports вірно, pickle спробує зіставити старі імена Python 2 з новими іменами, які використовуються в Python 3. The кодування та помилки підказують маринуванню, як розшифрувати 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.0datetime , вилучення даних об’єкта Python 2 порушено, якщо ви не використовуєте encoding='bytes'.


1
Як це можна зробити назад сумісним з Python 2? Мабуть, аргументу кодування немає для Python 2.
EpicAdv

2
@EpicAdv: вам не потрібно робити цей код сумісним з Python 2; це питання стосується того, як завантажувати соління Python 2 на Python 3. Залиште загальне encodingключове слово для Python 2.
Martijn Pieters

10
@EpicAdv: Ви можете створити словник pickle_options, який порожній для python 2 або має 'encoding': 'latin1'та надсилає ** pickle_options на маринування. Таким чином він повинен працювати в обох версіях.
труба

@pipefish - Розумний, але десь потрібно виявити, яку версію ви використовуєте, тож ви також могли б простіше просто зробити дзвінок по-різному (один з і один без зайвого аргументу) залежно від версії. Але принаймні ви отримали суть коментаря EpicAdv, котрий коментар Мартійна зовсім не стосується.
Джон Y

2
Я усвідомлюю, що datetimeкоментар не був головним змістом цієї відповіді, але для майбутніх читачів я хотів би зазначити, що навіть "виправлені" версії Python 3 все ще потребують encoding='latin-1'скасування дати дати Python 2. Якщо ваші мариновані дані Python 2 включають як дати, так і бітестріли, закодовані в чомусь іншому, ніж Latin-1, то вам все-таки краще скористатися encoding='bytes'.
Джон Y

15

Використання encoding='latin1'викликає деякі проблеми, коли ваш об'єкт містить нумеровані масиви.

Використання encoding='bytes'буде краще.

Будь ласка, дивіться цю відповідь для повного пояснення використанняencoding='bytes'


Які питання? Що я повинен бути обережним? використання bytesробить рядки в байти (), тому я вважаю latin1за краще, якщо це можливо, але мені незрозуміло, у чому проблема.
Гульзар

2
@ sreeragh-ar: Чи можете ви навести приклад проблем, з якими ви стикалися? У мене двовимірний numpy.ndarray(numpy 1.14) маринований в Python 2.7, використовуючи cPickle.dumps(), і вилучення в Python 3 із pickle.loads(..., encoding='latin1')відмінною роботою.
djvg

@djvg Я зіткнувся з проблемами, коли мені довелося підбирати зображення у вигляді рядка зображення та знімати їх. Код можна знайти тут. gist.github.com/sreeragh-ar/70205db3a43badbfa69f758faa898be3
Sreeragh AR

@Gulzar Будь ласка, дивіться вищевказану суть проблеми. Після видалення зображення зображення зіпсувалися.
Sreeragh AR
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.