Как загрузить объект в рассол? - PullRequest
0 голосов
/ 05 марта 2019

Я пытаюсь загрузить маринованный словарь, но получаю ошибку атрибута, такую ​​как эта

TypeError: a bytes-like object is required, not '_io.BufferedReader'

Ниже приведен код для чтения и записи объекта pickle. Я сбрасываю засоленные объекты на рабочую станцию ​​Linux с Python 2.7.12. Данные переносятся на Mac с python 3.6.4, где выполняется readTrueData (), что приводит к указанной выше ошибке.

def readTrueData(name):
    fName = str('trueData/'+name+'.pkl')
    f = open(fName,'rb')
    #    print(f)
    #    print(type(f))
    pC = pickle.loads(f)
    return pC

def storeTrueData(atomicConfigs, name):
    import quippy
    storeDic = {}
    #rangeKeys = len(atomicConfigs)
    #print(rangeKeys)
    qTrain = quippy.AtomsList(atomicConfigs)
    print(len(qTrain))
    rangeKeys = len(qTrain)
    print(rangeKeys)
    for i in range(rangeKeys):
        #configConsidered = atomicConfigs[i]
        trueForce = np.array(qTrain[i].force).T
        storeDic[i] = trueForce
    f = open("trueData/"+ name + ".pkl", "wb")
    pickle.dump(storeDic, f)
    f.close()    
    return None

UPDATE

Работая над предложениями, упомянутыми в комментариях, я изменил свой код, как показано ниже а.) pC = pickle.load(f) б.) pC = pickle.loads(f.read()) В обоих случаях я получил следующую ошибку

UnicodeDecodeError: 'ascii' codec can't decode byte 0x87 in position 1: ordinal not in range(128)

Ответы [ 3 ]

1 голос
/ 05 марта 2019

pC = pickle.loads(f.read()) - это то, что вы ищете, но вы действительно должны использовать контекст with :

with open(fName, 'rb') as f: 
    pC = pickle.loads(f.read())

Это обеспечит правильное закрытие файла,тем более, что в вашем коде нет функции f.close().

1 голос
/ 05 марта 2019

Ваша первая проблема вызвана несоответствием между типом аргумента и выбранным load* методом; loads ожидает bytes объектов, load ожидает самого файлового объекта. Передача файлового объекта в loads является причиной вашей ошибки.

Другая проблема связана с проблемой совместимости версий с типами numpy и datetime; Python 2 выбирает str s без заданной кодировки, но Python 3 должен разблокировать их с известной кодировкой (или 'bytes', чтобы получить необработанный bytes вместо str). Для типов numpy и datetime, необходимо пройти encoding='latin-1':

Необязательные ключевые аргументы: fix_imports, кодировка и ошибки, которые используются для управления поддержкой совместимости для потока pickle, сгенерированного Python 2. Если fix_imports имеет значение true, pickle попытается сопоставить старые имена Python 2 с новыми именами, используемыми в Python. 3. Кодирование и ошибки сообщают pickle, как декодировать экземпляры 8-битных строк, выбранные Python 2; по умолчанию они имеют значения «ASCII» и «строгий» соответственно. Кодировка может быть «байтами» для чтения этих 8-битных строковых экземпляров в виде байтовых объектов. Использование encoding = 'latin1' требуется для удаления массивов NumPy и экземпляров datetime, date и time, выбранных Python 2.

В любом случае исправление должно измениться:

def readTrueData(name):
    fName = str('trueData/'+name+'.pkl')
    f = open(fName,'rb')
    #    print(f)
    #    print(type(f))
    pC = pickle.loads(f)
    return pC

до:

def readTrueData(name):
    fName = str('trueData/'+name+'.pkl')
    with open(fName, 'rb') as f:  # with statement avoids file leak
        # Match load with file object, and provide encoding for Py2 str
        return pickle.load(f, encoding='latin-1')

Из соображений корректности и производительности я бы также рекомендовал изменить pickle.dump(storeDic, f) на pickle.dump(storeDic, f, protocol=2) на компьютере с Python 2, чтобы поток генерировался с использованием более современного протокола Pickle, который позволяет эффективно выбирать массивы numpy среди другие вещи. Протокол 0, по умолчанию в Python 2, не может использовать верхний бит каждого байта (он совместим с ASCII), что означает, что необработанные двоичные данные резко раздуваются в протоколе 0, требуя тонны битовых сдвигов, где протокол 2 может сбросить их в необработанном виде. Протокол 2 также является единственным протоколом Py2, который эффективно выбирает новые классы стилей, и единственным, который может правильно выбирать определенные типы экземпляров (например, с использованием __slots__ / __new__ и т. П.).

Я бы также порекомендовал сценарий начать с:

try:
    import cPickle as pickle
except ImportError:
    import pickle

, как и в Python 2, pickle реализован на чистом Python, и он медленный и не может использовать некоторые из более эффективных кодов выбора. На Python 3 cPickle исчезает, но pickle автоматически ускоряется. Между этим и использованием протокола 2 травление на машине Python 2 должно работать на намного быстрее и производить намного меньших солений.

1 голос
/ 05 марта 2019

Вы должны использовать pickle.load(...) для чтения, если используете open таким образом.

Источник: https://docs.python.org/3/library/pickle.html

...