Reputation: 4677
The following code works in Python 2.7:
import os
import pickle
modelpath = "models/"
gmm_files = [os.path.join(modelpath,fname) for fname in
os.listdir(modelpath) if fname.endswith('.gmm')]
models = [pickle.load(open(fname,'r')) for fname in gmm_files]
However, when I run the code in Python3, I get the following error from the last line:
TypeError: a bytes-like object is required, not 'str'
In order to get a better idea, I tried printing print([type(open(fname,'r')) for fname in gmm_files])
in both versions and found out that in python 2 the type is <type 'file'>
and in Python 3 the type is <class '_io.TextIOWrapper'>
.
I've checked out these stackoverflow questions but neither of them have helpful answers for this:
python 3.5: TypeError: a bytes-like object is required, not 'str' when writing to a file
Python sockets error TypeError: a bytes-like object is required, not 'str' with send function
UPDATE
A bunch of the answers here said to change open(fname, 'r')
to open(fname, 'rb')
but that just leads to another error: UnicodeDecodeError: 'ascii' codec can't decode byte 0xc0 in position 0: ordinal not in range(128)
Upvotes: 1
Views: 924
Reputation: 6190
Ref https://docs.python.org/3.6/library/pickle.html#pickle.load, the file-like object you pass to pickle.load
needs to return binary data. Files are opened in text-mode by default, which is why you're seeing this error. If you open the file in binary mode (by adding 'b'
to the mode), everything should be work.
E.g.
models = [pickle.load(open(fname, 'rb')) for fname in gmm_files]
Upvotes: 2
Reputation: 44838
As the documentation for the pickle.load
method says (emphasis mine):
The argument file must have two methods, a read() method that takes an integer argument, and a readline() method that requires no arguments. Both methods should return bytes.
open(stuff, 'r')
will open the file for reading text, not raw bytes. Thus, open(stuff, 'r').read
will return str
, not bytes
. To fix that, open the file in binary mode: open(stuff, 'rb')
.
Upvotes: 2