Zastanawiam się, czy istnieje sposób na załadowanie obiektu, który został wytrawiony w Pythonie 2.4 za pomocą Pythona 3.4.
Używałem 2to3 na dużej ilości starszego kodu firmy, aby go zaktualizować.
Po wykonaniu tej czynności podczas uruchamiania pliku pojawia się następujący błąd:
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)
Patrząc na marynowany obiekt będący w sprzeczności, jest to a dict
in a dict
, zawierający klucze i wartości typu str
.
Moje pytanie brzmi: czy istnieje sposób na załadowanie obiektu, pierwotnie wytrawionego w Pythonie 2.4, za pomocą Pythona 3.4?
json
moduł? Być może mógłbyś napisać skrypt 2.4, który odblokowuje obiekt i zapisuje go jako obiekt json, a następnie napisać skrypt 3.4, który odczytuje obiekt json i zapisuje go jako obiekt pickle zgodny z 3.4. Byłaby to jednorazowa operacja, którą wykonujesz na wszystkich swoich plikach marynat.Odpowiedzi:
Będziesz musiał powiedzieć,
pickle.load()
jak przekonwertować dane testowe Pythona na ciągi Python 3 lub możeszpickle
zostawić je jako bajty.Domyślnie próbuje się zdekodować wszystkie dane łańcuchowe jako ASCII, a dekodowanie kończy się niepowodzeniem. Zobacz
pickle.load()
dokumentację :Ustawienie kodowania na
latin1
umożliwia bezpośredni import danych:with open(mshelffile, 'rb') as f: d = pickle.load(f, encoding='latin1')
ale musisz sprawdzić, czy żaden z twoich ciągów nie jest dekodowany przy użyciu niewłaściwego kodeka; Latin-1 działa dla każdego wejścia, ponieważ bezpośrednio mapuje wartości bajtów 0-255 na pierwsze 256 punktów kodowych Unicode.
Alternatywą byłoby załadowanie danych i późniejsze
encoding='bytes'
zdekodowanie wszystkichbytes
kluczy i wartości.Zauważ, że do wersji Pythona wcześniejszych niż 3.6.8, 3.7.2 i 3.8.0 usuwanie
datetime
danych obiektu Python 2 jest przerywane, chyba że używaszencoding='bytes'
.źródło
encoding
Całkowicie upuść słowo kluczowe dla Pythona 2.'encoding': 'latin1'
i wysyła ** pickle_options do pickle. W ten sposób powinien działać w obu wersjach.datetime
komentarz nie był głównym motywem tej odpowiedzi, ale dla przyszłych czytelników chciałbym zwrócić uwagę, że nawet „naprawione” wersje Pythona 3 nadal wymagająencoding='latin-1'
odblokowania czasów danych w Pythonie 2. Jeśli twoje marynowane dane Pythona 2 zawierają zarówno czas danych, jak i bajty zakodowane w czymś innym niż Latin-1, to mimo wszystko może być lepiejencoding='bytes'
.Używanie
encoding='latin1'
powoduje pewne problemy, gdy twój obiekt zawiera tablice numpy.Korzystanie
encoding='bytes'
będzie lepsze.Zapoznaj się z tą odpowiedzią, aby uzyskać pełne wyjaśnienie użycia
encoding='bytes'
źródło
bytes
zamienia łańcuchy w bajty (), więc wolę,latin1
jeśli to możliwe, ale nie jest dla mnie jasne, na czym polega problem.numpy.ndarray
(numpy 1.14) marynowany w Pythonie 2.7 przy użyciucPickle.dumps()
i rozpakowywanie w Pythonie 3 zpickle.loads(..., encoding='latin1')
działa dobrze.