Я створив такий об’єкт:
company1.name = 'banana'
company1.value = 40
Я хотів би зберегти цей об’єкт. Як я можу це зробити?
protocol=pickle.HIGHEST_PROTOCOL
. Моя відповідь також дає альтернативи соління.
Я створив такий об’єкт:
company1.name = 'banana'
company1.value = 40
Я хотів би зберегти цей об’єкт. Як я можу це зробити?
protocol=pickle.HIGHEST_PROTOCOL
. Моя відповідь також дає альтернативи соління.
Відповіді:
Ви можете використовувати pickle
модуль у стандартній бібліотеці. Ось елементарне застосування його до вашого прикладу:
import pickle
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
with open('company_data.pkl', 'wb') as output:
company1 = Company('banana', 40)
pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
company2 = Company('spam', 42)
pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as input:
company1 = pickle.load(input)
print(company1.name) # -> banana
print(company1.value) # -> 40
company2 = pickle.load(input)
print(company2.name) # -> spam
print(company2.value) # -> 42
Ви також можете визначити власну просту утиліту, наприклад наступну, яка відкриває файл і записує до нього один об'єкт:
def save_object(obj, filename):
with open(filename, 'wb') as output: # Overwrites any existing file.
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
# sample usage
save_object(company1, 'company1.pkl')
Оскільки це така популярна відповідь, я хотів би торкнутися кількох дещо розширених тем використання.
cPickle
(або _pickle
) протиpickle
Практично завжди краще використовувати cPickle
модуль, а не pickle
тому, що перший пишеться на С та набагато швидше. Існують деякі тонкі відмінності між ними, але в більшості ситуацій вони еквівалентні, а версія С забезпечить значно кращі показники. Перехід на нього не може бути простішим, просто змініть import
заяву на це:
import cPickle as pickle
У Python 3 cPickle
було перейменовано _pickle
, але робити це вже не потрібно, оскільки pickle
тепер модуль робить це автоматично - див. Яка різниця між pickle та _pickle у python 3? .
Ви можете використовувати щось на кшталт наступного, щоб переконатися, що ваш код завжди буде використовувати версію C, коли вона доступна і в Python 2 і 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
може читати і записувати файли в декількох різних, специфічних для Python, форматах, званих протоколами, як описано в документації , "Протокол версії 0" є ASCII і тому "читабельний для людини". Версії> 0 є двійковими, і найвищий доступний залежить від того, яка версія Python використовується. За замовчуванням також залежить версія Python. У Python 2 за замовчуванням була версія протоколу 0
, але в Python 3.8.1 це версія протоколу 4
. У Python 3.x модуль був pickle.DEFAULT_PROTOCOL
доданий до нього, але цього не існує в Python 2.
На щастя, pickle.HIGHEST_PROTOCOL
у кожному дзвінку є стенограма для запису (якщо припустити, що ви хочете, і зазвичай це робите), просто використовуйте буквальне число -1
- аналогічно посиланням на останній елемент послідовності за допомогою негативного індексу. Отже, замість того, щоб писати:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Ви можете просто написати:
pickle.dump(obj, output, -1)
У будь-якому випадку, вам слід було б вказати протокол лише один раз, якщо ви створили Pickler
об'єкт для використання в кількох операціях маринування:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Примітка . Якщо ви знаходитесь в середовищі, де використовуються різні версії Python, ви, ймовірно, захочете явно використовувати (тобто жорсткий код) певний номер протоколу, який вони можуть прочитати (пізніші версії, як правило, можуть читати файли, створені попередніми) .
Хоча файл підберезника може містити будь-яку кількість маринованих об'єктів, як показано у наведених вище зразках, коли їх невідома кількість, часто простіше зберігати їх у якомусь контейнері зі змінним розміром, як list
, наприклад tuple
, або dict
записувати всі вони у файл за один виклик:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
і відновіть список і все, що в ньому пізніше, за допомогою:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
Основна перевага полягає в тому, що вам не потрібно знати, скільки об'єктів збережено, щоб потім їх знову завантажити (хоча це можливо і без цієї інформації , можливо, потрібен деякий трохи спеціалізований код). Дивіться відповіді на відповідне запитання Збереження та завантаження декількох об’єктів у файл маринування? для детальної інформації про різні способи зробити це. Особисто я , як @Lutz Prechelt в відповідь на краще. Ось він адаптований до прикладів тут:
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickled_items(filename):
""" Unpickle a file of pickled data. """
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Companies in pickle file:')
for company in pickled_items('company_data.pkl'):
print(' name: {}, value: {}'.format(company.name, company.value))
company1
та company2
. Чому ви також не видалите Company
і не покажете, що відбувається?
Я думаю, що це досить сильне припущення вважати, що об'єкт є class
. Що робити, якщо це не class
? Існує також припущення, що об'єкт не був визначений в інтерпретаторі. Що робити, якщо це було визначено в перекладачі? Крім того, що робити, якщо атрибути додаються динамічно? Коли деякі об’єкти python мають атрибути, додані до їх __dict__
після створення, pickle
не поважає додавання цих атрибутів (тобто він "забуває", вони були додані - тому що pickle
серіалізується за посиланням на визначення об'єкта).
У всіх цих випадках pickle
і cPickle
може вас жахливо зірвати.
Якщо ви хочете зберегти object
(довільно створений), де у вас є атрибути (або додані у визначенні об'єкта, або згодом) ... найкраще скористатись цією пропозицією - використовувати dill
, що може серіалізувати майже що завгодно в python.
Починаємо з класу ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
Тепер вимкніть та перезапустіть ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> with open('company.pkl', 'rb') as f:
... company1 = pickle.load(f)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'Company'
>>>
На жаль ... pickle
не вдається це впоратися. Давайте спробуємо dill
. Ми накинемо на інший об’єкт типу (а lambda
) для гарної міри.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
А тепер прочитайте файл.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> with open('company_dill.pkl', 'rb') as f:
... company1 = dill.load(f)
... company2 = dill.load(f)
...
>>> company1
<__main__.Company instance at 0x107909128>
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
Це працює. Причина pickle
не вдається, і dill
ні, полягає в тому, що dill
трактує __main__
як модуль (здебільшого), а також може вибирати визначення класу замість маринування за посиланням (як pickle
це робиться). Причина, яка dill
може підберуть а, lambda
- це те, що вона дає їй назву ... тоді магія маринування може статися.
Насправді, існує простіший спосіб зберегти всі ці об’єкти, особливо якщо у вас багато створених об’єктів. Просто скиньте весь сеанс пітона та поверніться до нього пізніше.
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
Тепер вимкніть комп’ютер, насолоджуйтесь еспресо чи будь-яким іншим, і повертайтеся пізніше ...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
Єдиний головний недолік - це те, що dill
він не є частиною стандартної бібліотеки python. Отже, якщо ви не можете встановити пакет python на своєму сервері, ви не можете його використовувати.
Однак якщо ви зможете встановити пакети python у вашій системі, ви можете отримати останню версію за dill
допомогою git+https://github.com/uqfoundation/dill.git@master#egg=dill
. І ви можете отримати останню випущену версію за допомогою pip install dill
.
TypeError: __new__() takes at least 2 arguments (1 given)
намагаюся використовувати dill
(що виглядає перспективно) з досить складним об'єктом, який включає аудіофайл.
TypeError
коли саме робите щось? Зазвичай це ознака неправильної кількості аргументів при інстанціюванні екземпляра класу. Якщо це не є частиною робочого процесу вищевказаного питання, чи можете ви надіслати його як інше запитання, надіслати його електронною поштою або додати його як проблему на сторінці dill
github?
dill
проблемою.
dil
Я все-таки дає мені MemoryError
! так само cPickle
, pickle
і hickle
.
Ви можете використовувати будь-який кеш, щоб зробити роботу за вас. Він враховує всі деталі:
pickle
модуль python для обробки lambda
та всі приємні функції python.Припустимо, що у вас є функція, myfunc
яка створює екземпляр:
from anycache import anycache
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')
def myfunc(name, value)
return Company(name, value)
Anycache зателефонує myfunc
в перший раз і підбирає результат до файлу, cachedir
використовуючи унікальний ідентифікатор (залежно від назви функції та її аргументів) як імені файлу. При будь-якому послідовному виконанні маринований предмет завантажується. Якщо cachedir
збережено значення між прогонами python, маринований об'єкт береться з попереднього запуску python.
Детальнішу інформацію можна знайти в документації
anycache
для збереження більше одного екземпляра, скажімо, class
контейнера, такого як list
(це не було результатом виклику функції)?
Короткий приклад з використанням company1
вашого запитання, з python3.
import pickle
# Save the file
pickle.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = pickle.load(open("company1.pickle", "rb"))
Однак, як зазначила ця відповідь , соління часто не вдається. Тож вам слід справді користуватися dill
.
import dill
# Save the file
dill.dump(company1, file = open("company1.pickle", "wb"))
# Reload the file
company1_reloaded = dill.load(open("company1.pickle", "rb"))