Збереження та завантаження предметів та використання соління


114

Я намагаюся зберігати та завантажувати об'єкти за допомогою 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

Я не знаю, що робити, тому що я не розумію цього повідомлення. Хтось знає, як я можу завантажувати мій предмет «банан»? Дякую!

РЕДАКТИРУЙТЕ: Як деякі з вас просили, я поставив:

>>> 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


Відповіді:


74

Що стосується вашої другої проблеми:

 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 - це швидша реалізація модуля соління в 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}

Яка структура даних це 'd = {"a": 1, "b": 2}'?
Пітерстоун

1
@Peterstone: {"a": 1, "b": 2}створює словник з ключами "a"та "b"в ньому. Це називається виразом відображення словника в онлайн-документації. Це лише один з декількох різних способів об'єкта типу dict, який є одним із кількох стандартних вбудованих типів даних, доступних у Python.
мартіно

2
Чому буква 'r' переходить до назви файла? Я цього не бачу в документах. Крім того, це ускладнює використання змінної для імені файлу.
SherylHohman

7
Дивлячись на цю відповідь сьогодні та помічаючи, вона стосується лише Python 2.x. У Python 3.x слід безпосередньо використовувати pickleте, що імпортуватиметься cpickleавтоматично, якщо можна. docs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp

41

Наступні роботи для мене:

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

Це працює на мене, але я намагаюся закрити сеанс, відкрити новий і завантажити те, що я заощаджую на минулому сеансі. Закриваю сеанс після введення рядка "filehandler.close ()" і відкриваю новий, і вкладаю решту вашого коду, потім після введення "object_file = pickle.load (файл)" я отримую цю помилку: Traceback ( останній дзвінок останній): Файл "<pyshell # 5>", рядок 1, у <module> object_file = pickle.load (файл) Файл "C: \ Python31 \ lib \ pickle.py", рядок 1365, в кодуванні завантаження = кодування, помилки = помилки) .load () AttributeError: 'Модуль' об’єкта не має атрибута 'Фрукти'
Peterstone

3
@Peterstone: На другому сеансі вам потрібно буде визначити class Fruitsвизначення, яке pickle.load()зможе відновити об'єкт із даних, збережених у двійковому файлі. Найкращою практикою для подібних речей є розміщення class Fruitsвизначення в окремому файлі .py (що робить його спеціальним модулем), а потім importцей модуль або елементи з нього, коли це потрібно (тобто обидва сеанси). Наприклад, якщо ви помістите його у файл з назвою, MyDataDefs.pyто можете написати from MyDataDefs import Fruits. Повідомте мене, якщо це незрозуміло, і я відповідно оновлю свою відповідь.
мартіно

Насправді PEP 8 рекомендує використовувати всі малі символи для імен модулів, тому приклад наприкінці мого останнього коментаря повинен був бути у файлі, названому з my_data_defs.pyвикористанням from my_data_defs import Fruits.
мартино

24

Ви також забули прочитати це як двійкове.

У своїй частині написання у вас є:

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)

1
Я використовую вашу версію, яка використовує оператор with, і отримую це повідомлення: Traceback (останній дзвінок останній): Файл "<pyshell # 20>", рядок 1, у <module> print (banana.color) AttributeError: 'Fruits' об’єкт не має атрибута 'color'
Peterstone

17

У цьому випадку завжди відкривайте у двійковому режимі

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

6

Ви не відкрили файл у двійковому режимі.

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

Треба працювати.

Що стосується вашої другої помилки, файл, швидше за все, порожній, а це означає, що ви ненавмисно очистили його або використали неправильне ім’я файлу чи щось.

(Це припущення, що ви дійсно закрили сеанс. Якщо ні, то це тому, що ви не закрили файл між записом і прочитаним).

Я перевірив ваш код, і він працює.


3

Здається, ви хочете зберегти екземпляри свого класу на сесіях, і pickleце гідний спосіб зробити це. Однак є пакет під назвою, kleptoякий резюмує збереження об’єктів у інтерфейсі словника, тож ви можете вибрати об'єкти та зберегти їх у файл (як показано нижче), або забрати об'єкти та зберегти їх у базу даних, або замість цього використовуйте соління json або багато інших варіантів. Приємно в тому klepto, що, використовуючи загальний інтерфейс, це робить його легким, тому вам не потрібно пам’ятати деталі низького рівня, як зберегти за допомогою маринування до файлу чи іншим способом.

Зауважте, що він працює для динамічно доданих атрибутів класу, які маринувати не можуть ...

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


1

Ви можете використовувати будь-який кеш, щоб зробити роботу за вас. Припустимо, що у вас є функція, 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збережено значення між прогонами python, маринований об'єкт береться з попереднього запуску python.

Аргументи функції також враховуються. Аналогічним чином працює реабілітаційна реалізація:

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.