Сохранение и загрузка объектов и использование рассола - PullRequest
80 голосов
/ 25 декабря 2010

Я пытаюсь сохранить и загрузить объекты с помощью модуля pickle.
Сначала я объявляю свои объекты:

>>> class Fruits:pass
...
>>> banana = Fruits()

>>> banana.color = 'yellow'
>>> banana.value = 30

После этого я открываю файл с именем «Fruits.obj» (ранее я создал новый файл .txt и переименовал в «Fruits.obj»):

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)

После этого я закрываю свою сессию, начинаю новую и ставлю следующую (пытаюсь получить доступ к объекту, который он должен был сохранить):

file = open("Fruits.obj",'r')
object_file = pickle.load(file)

Но у меня есть это сообщение:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
ValueError: read() from the underlying stream did notreturn bytes

Я не знаю, что делать, потому что я не понимаю этого сообщения. Кто-нибудь знает, как я могу загрузить свой объект «банан»? Спасибо!

EDIT: Как некоторые из вас предложили, я поставил:

>>> import pickle
>>> file = open("Fruits.obj",'rb')

Не было никаких проблем, но следующее, что я поставил, было:

>>> object_file = pickle.load(file)

А у меня ошибка:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError

Ответы [ 7 ]

61 голосов
/ 25 декабря 2010

Что касается вашей второй проблемы:

 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "C:\Python31\lib\pickle.py", line
 1365, in load encoding=encoding,
 errors=errors).load() EOFError

После прочтения содержимого файла указатель файла будет находиться в конце файла - дальнейших данных для чтения не будет. Вам нужно перемотать файл, чтобы он снова был прочитан с начала:

file.seek(0)

Что вы обычно хотите сделать, так это использовать менеджер контекста, чтобы открыть файл и прочитать данные из него. Таким образом, файл будет автоматически закрыт после завершения выполнения блока, что также поможет вам организовать ваши файловые операции в значимые куски.

Наконец, cPickle - более быстрая реализация модуля pickle в C. Итак:

In [1]: import cPickle

In [2]: d = {"a": 1, "b": 2}

In [4]: with open(r"someobject.pickle", "wb") as output_file:
   ...:     cPickle.dump(d, output_file)
   ...:

# pickle_file will be closed at this point, preventing your from accessing it any further

In [5]: with open(r"someobject.pickle", "rb") as input_file:
   ...:     e = cPickle.load(input_file)
   ...:

In [7]: print e
------> print(e)
{'a': 1, 'b': 2}
30 голосов
/ 26 декабря 2010

У меня работает следующее:

class Fruits: pass

banana = Fruits()

banana.color = 'yellow'
banana.value = 30

import pickle

filehandler = open("Fruits.obj","wb")
pickle.dump(banana,filehandler)
filehandler.close()

file = open("Fruits.obj",'rb')
object_file = pickle.load(file)
file.close()

print(object_file.color, object_file.value, sep=', ')
# yellow, 30
17 голосов
/ 25 декабря 2010

Вы также забываете читать его в двоичном виде.

В вашей части записи у вас есть:

open(b"Fruits.obj","wb") # Note the wb part (Write Binary)

В части чтения у вас есть:

file = open("Fruits.obj",'r') # Note the r part, there should be a b too

Так что замените его на:

file = open("Fruits.obj",'rb')

И это будет работать:)


Что касается вашей второй ошибки, она, скорее всего, вызвана неправильным закрытием / синхронизацией файла.

Попробуйте этот фрагмент кода, чтобы написать:

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)
>>> filehandler.close()

И это (без изменений) читать:

>>> import pickle
>>> file = open("Fruits.obj",'rb')
>>> object_file = pickle.load(file)

Более аккуратная версия будет использовать with Выписка.

Для записи:

>>> import pickle
>>> with open('Fruits.obj', 'wb') as fp:
>>>     pickle.dump(banana, fp)

Для чтения:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)
12 голосов
/ 25 декабря 2010

Всегда открывать в двоичном режиме, в этом случае

file = open("Fruits.obj",'rb')
4 голосов
/ 25 декабря 2010

Вы не открыли файл в двоичном режиме.

open("Fruits.obj",'rb')

Должно работать.

Для вашей второй ошибки файл, скорее всего, пуст, что означает, что вы случайно удалили его или использовали неправильное имя файла или что-то в этом роде.

(Предполагается, что вы действительно закрыли сеанс. Если нет, то это потому, что вы не закрыли файл между записью и чтением).

Я проверил ваш код, и он работает.

2 голосов
/ 21 мая 2014

Кажется, вы хотите сохранить экземпляры классов между сеансами, и использование pickle - достойный способ сделать это. Тем не менее, есть пакет с именем klepto, который абстрагирует сохранение объектов в интерфейс словаря, поэтому вы можете выбрать выбор объектов и сохранить их в файл (как показано ниже) или выбрать объекты и сохранить их в базе данных, или вместо использования pickle используйте json, или много других опций. Приятной особенностью klepto является то, что благодаря абстракции к общему интерфейсу это облегчает задачу, поэтому вам не нужно запоминать низкоуровневые подробности о том, как сохранять с помощью протравливания в файл или иным образом.

Обратите внимание, что это работает для динамически добавляемых атрибутов класса, которые не могут делать pickle ...

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive 
>>> db = file_archive('fruits.txt')
>>> class Fruits: pass
... 
>>> banana = Fruits()
>>> banana.color = 'yellow'
>>> banana.value = 30
>>> 
>>> db['banana'] = banana 
>>> db.dump()
>>> 

Затем мы перезапускаем…

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('fruits.txt')
>>> db.load()
>>> 
>>> db['banana'].color
'yellow'
>>> 

Klepto работает на python2 и python3.

Получить код здесь: https://github.com/uqfoundation

0 голосов
/ 19 ноября 2017

Вы можете использовать anycache , чтобы сделать работу за вас. Предполагая, что у вас есть функция myfunc, которая создает экземпляр:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc()
    banana = Fruits()
    banana.color = 'yellow'
    banana.value = 30
return banana

Anycache в первый раз вызывает myfunc и выводит результат на файл в cachedir с использованием уникального идентификатора (в зависимости от имени функции и аргументов) в качестве имени файла. При любом последовательном прогоне засоленный объект загружается.

Если между прогонами питона сохраняется cachedir, то выбранный объект берется из предыдущего прогона питона.

Аргументы функции также принимаются во внимание. Реорганизованная реализация работает аналогично:

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc(color, value)
    fruit = Fruits()
    fruit.color = color
    fruit.value = value
return fruit
...