Unpickling a python 2 object with python 3
You'll have to tell pickle.load()
how to convert Python bytestring data to Python 3 strings, or you can tell pickle
to leave them as bytes.
The default is to try and decode all string data as ASCII, and that decoding fails. See the 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.
Setting the encoding to latin1
allows you to import the data directly:
with open(mshelffile, 'rb') as f:
d = pickle.load(f, encoding='latin1')
but you'll need to verify that none of your strings are decoded using the wrong codec; Latin-1 works for any input as it maps the byte values 0-255 to the first 256 Unicode codepoints directly.
The alternative would be to load the data with encoding='bytes'
, and decode all bytes
keys and values afterwards.
Note that up to Python versions before 3.6.8, 3.7.2 and 3.8.0, unpickling of Python 2 datetime
object data is broken unless you use encoding='bytes'
.
Passing a python object from a python2 script to python3 script
The binary representation of dictionaries, and in fact objects in general, has changed quite a bit between Python 2 and Python 3. That means that you will not be able to use the objects directly between versions of Python. Some form of serialization to a mutually acceptable format will be necessary.
The JSON format you are using fits this criterion. I would recommend sticking with it as it is flexible, human readable and quite general.
If space becomes an issue, you can look into pickling as an alternative, but I would not recommend it as a first choice. While pickle.load
can understand Python 2 data just fine, there are many caveats to keep in mind with different interpretations of datatypes between Python versions, especially bytes
: Unpickling a python 2 object with python 3
Here is a resource that may help you with some common errors from unpicking on the Python 3 side: TypeError: a bytes-like object is required, not 'str' when opening Python 2 Pickle file in Python 3
Unpickling classes from Python 3 in Python 2
This problem is Python issue 3675. This bug is actually fixed in Python 3.11.
If we import:
from lib2to3.fixes.fix_imports import MAPPING
MAPPING maps Python 2 names to Python 3 names. We want this in reverse.
REVERSE_MAPPING={}
for key,val in MAPPING.items():
REVERSE_MAPPING[val]=key
We can override the Unpickler and loads
class Python_3_Unpickler(pickle.Unpickler):
"""Class for pickling objects from Python 3"""
def find_class(self,module,name):
if module in REVERSE_MAPPING:
module=REVERSE_MAPPING[module]
__import__(module)
mod = sys.modules[module]
klass = getattr(mod, name)
return klass
def loads(str):
file = pickle.StringIO(str)
return Python_3_Unpickler(file).load()
We then call this loads instead of pickle.loads.
This should solve the problem.
Related Topics
What's the Difference Between %S and %D in Python String Formatting
Find First Element in a Sequence That Matches a Predicate
Can Python Pickle Lambda Functions
Transparent Background in a Tkinter Window
Cs50: Like Operator, Variable Substitution with % Expansion
Django - How to Create a File and Save It to a Model's Filefield
Execute a File with Arguments in Python Shell
What Is the Return Value of Os.System() in Python
Restart Cumsum and Get Index If Cumsum More Than Value
Running Python on Windows for Node.Js Dependencies
Spark Dataframe Distinguish Columns with Duplicated Name
Split a Generator into Chunks Without Pre-Walking It
Find the Recaptcha Element and Click on It -- Python + Selenium
Convert to Binary and Keep Leading Zeros