Поскольку это такой популярный ответ, я бы хотел коснуться нескольких немного продвинутых тем использования.
cPickle(или _pickle) противpickle
Практически всегда предпочтительнее использовать cPickleмодуль, чем pickleтот, который написан на C и работает намного быстрее. Между ними есть некоторые тонкие различия, но в большинстве случаев они эквивалентны, и версия C обеспечит значительно более высокую производительность. Переход на это не может быть проще, просто измените importутверждение на это:
Вкратце вы можете использовать что-то вроде следующего, чтобы гарантировать, что ваш код всегда будет использовать версию C, когда она доступна как в Python 2, так и в 3:
try:import cPickle as pickleexceptModuleNotFoundError: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объект для использования в нескольких операциях рассола:
Примечание . Если вы работаете в среде, в которой работают разные версии Python, вам, вероятно, захочется явно использовать (т. Е. Использовать жесткий код) конкретный номер протокола, который все они могут прочитать (более поздние версии обычно могут читать файлы, созданные более ранними версиями) ,
Несколько объектов
В то время как рассол файл может содержать любое количество соленых объектов, как показано в примерах выше, когда есть неизвестное число из них, часто проще хранить их в каком - то контейнер переменно размера, подобно list, tupleили dictи писать все они в файл за один вызов:
и восстановить список и все в нем позже с помощью:
with open('tech_companies.pkl','rb')as input:
tech_companies = pickle.load(input)
Главное преимущество является то, что вам не нужно знать , сколько объекта экземпляров сохраняются для того , чтобы загрузить их позже (хотя это и без этой информации является возможным, требует немного специализированного кода). См. Ответы на связанный вопрос. Сохранение и загрузка нескольких объектов в файл pickle? для деталей о различных способах сделать это. Лично мне больше всего нравится ответ @Lutz Prechelt . Вот это адаптировано к примерам здесь:
classCompany:def __init__(self, name, value):
self.name = name
self.value = valuedef pickled_items(filename):""" Unpickle a file of pickled data. """with open(filename,"rb")as f:whileTrue:try:yield pickle.load(f)exceptEOFError:breakprint('Companies in pickle file:')for company in pickled_items('company_data.pkl'):print(' name: {}, value: {}'.format(company.name, company.value))
Это редкость для меня, потому что я представлял, что есть более простой способ сохранить объект ... Что-то вроде 'saveobject (company1, c: \ mypythonobjects)
Peterstone
4
@Peterstone: Если вы хотите сохранить только один объект, вам понадобится примерно вдвое меньше кода, чем в моем примере - я специально написал это так, чтобы показать, как можно сохранить более одного объекта (и позже прочитать его). из) тот же файл.
Мартино
1
@ Питерстоун, есть очень веская причина для разделения обязанностей. Таким образом, нет никаких ограничений на то, как используются данные процесса травления. Вы можете сохранить его на диске или отправить по сетевому соединению.
Харальд Шейрих
3
@martinaeau, это было в ответ на замечание perstones о том, что для сохранения объекта на диске должна быть только одна функция. Ответственность за соленые огурцы заключается только в том, чтобы превратить объект в данные, которые могут быть обработаны как кусок. Запись вещей в файл является обязанностью файловых объектов. Отделяя вещи, можно обеспечить более высокое повторное использование, например, возможность посылать протравленные данные по сетевому соединению или сохранять их в базе данных, все обязанности отделены от фактической конвертации данных <->
Харальд Шейрих
1
Вы удаляете company1и company2. Почему бы вам не удалить Companyи не показать, что происходит?
Майк Маккернс
49
Я думаю, что это довольно сильное предположение, чтобы предположить, что объект является class. Что делать, если это не class? Есть также предположение, что объект не был определен в интерпретаторе. Что если это было определено в интерпретаторе? Кроме того, что если атрибуты были добавлены динамически? Когда некоторые объекты Python имеют атрибуты, добавленные к их __dict__после создания, pickleне учитывает добавление этих атрибутов (то есть он «забывает», что они были добавлены - потому что pickleсериализуется с помощью ссылки на определение объекта).
Во всех этих случаях вы pickleи cPickleможете ужасно подвести вас.
Если вы хотите сохранить object(произвольно созданный), где у вас есть атрибуты (добавленные в определении объекта или после) ... лучше всего использовать dill, который может сериализовать практически все в Python.
Начнем с класса…
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import pickle>>>classCompany:...pass...>>> company1 =Company()>>> company1.name ='banana'>>> company1.value =40>>>with open('company.pkl','wb')as f:... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)...>>>
Теперь выключите и перезапустите ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"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 loadreturnUnpickler(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) для хорошей меры.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"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.value40>>> company2.name'rhubarb'>>> company2.value42>>>
Оно работает. Причиной pickleсбоя и dillне является то, что он dillобрабатывает __main__как модуль (по большей части), а также может выбирать определения классов вместо выбора по ссылке (как pickleделает). Причина, по которой dillможно мариновать, lambdaсостоит в том, что она дает ему имя ... тогда может произойти магия маринования.
На самом деле, есть более простой способ сохранить все эти объекты, особенно если у вас есть много созданных вами объектов. Просто выкиньте весь сеанс Python и вернитесь к нему позже.
Теперь выключите компьютер, выпейте эспрессо или еще что-нибудь и зайдите позже ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwinType"help","copyright","credits"or"license"for more information.>>>import dill>>> dill.load_session('dill.pkl')>>> company1.name'banana'>>> company1.value40>>> company2.name'rhubarb'>>> company2.value42>>> 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(что выглядит многообещающе) с довольно сложным объектом, который включает в себя аудиофайл.
MikeiLL
1
@MikeiLL: Ты получаешь, TypeErrorкогда делаешь что, точно? Обычно это признак неверного количества аргументов при создании экземпляра класса. Если это не является частью рабочего процесса, описанного выше, не могли бы вы опубликовать его как другой вопрос, отправить его мне по электронной почте или добавить как проблему на dillстранице github?
Майк Маккернс
3
Для всех, кто подписался , вот соответствующий вопрос, который разместил @MikeLL - судя по всему, это не dillпроблема.
Мартино
dilЯ MemoryErrorдаю мне все же! так же cPickle, pickleи hickle.
Ферид Алиджани
4
Вы можете использовать anycache, чтобы сделать работу за вас. Он учитывает все детали:
Он использует укроп в качестве бэкэнда, который расширяет pickleмодуль Python для обработки lambdaи всех приятных возможностей Python.
Он хранит разные объекты в разных файлах и перезагружает их правильно.
Ограничивает размер кеша
Позволяет очистить кеш
Позволяет разделять объекты между несколькими прогонами
Позволяет уважать входные файлы, которые влияют на результат
Предполагая, что у вас есть функция, myfuncкоторая создает экземпляр:
from anycache import anycacheclassCompany(object):def __init__(self, name, value):
self.name = name
self.value = value@anycache(cachedir='/path/to/your/cache')def myfunc(name, value)returnCompany(name, value)
Anycache звонки myfuncв первый раз и соленье результата в файл с cachedirпомощью уникального идентификатора ( в зависимости от имени функции и ее аргументов) в качестве имени файла. При любом последовательном прогоне засоленный объект загружается. Если cachedirмежду запусками Python сохраняется, выбранный объект берется из предыдущего запуска Python.
Как можно использовать anycacheдля сохранения более одного экземпляра, скажем, classконтейнера или, например, такого list(который не был результатом вызова функции)?
Мартино
2
Быстрый пример использования 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"))
protocol=pickle.HIGHEST_PROTOCOL
. Мой ответ также дает альтернативу мариновать.Ответы:
Вы можете использовать
pickle
модуль в стандартной библиотеке. Вот элементарное применение этого к вашему примеру:Вы также можете определить свою собственную простую утилиту, например, которая открывает файл и записывает в него один объект:
Обновить
Поскольку это такой популярный ответ, я бы хотел коснуться нескольких немного продвинутых тем использования.
cPickle
(или_pickle
) противpickle
Практически всегда предпочтительнее использовать
cPickle
модуль, чемpickle
тот, который написан на C и работает намного быстрее. Между ними есть некоторые тонкие различия, но в большинстве случаев они эквивалентны, и версия C обеспечит значительно более высокую производительность. Переход на это не может быть проще, просто изменитеimport
утверждение на это:В Python 3
cPickle
был переименован_pickle
, но делать это больше не нужно, посколькуpickle
модуль теперь делает это автоматически - см. Какая разница между pickle и _pickle в python 3? ,Вкратце вы можете использовать что-то вроде следующего, чтобы гарантировать, что ваш код всегда будет использовать версию C, когда она доступна как в Python 2, так и в 3:
Форматы потока данных (протоколы)
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
- аналогично ссылке на последний элемент последовательности через отрицательный индекс. Итак, вместо того, чтобы писать:Вы можете просто написать:
В любом случае, вам нужно было бы указать протокол только один раз, если бы вы создали
Pickler
объект для использования в нескольких операциях рассола:Примечание . Если вы работаете в среде, в которой работают разные версии Python, вам, вероятно, захочется явно использовать (т. Е. Использовать жесткий код) конкретный номер протокола, который все они могут прочитать (более поздние версии обычно могут читать файлы, созданные более ранними версиями) ,
Несколько объектов
В то время как рассол файл может содержать любое количество соленых объектов, как показано в примерах выше, когда есть неизвестное число из них, часто проще хранить их в каком - то контейнер переменно размера, подобно
list
,tuple
илиdict
и писать все они в файл за один вызов:и восстановить список и все в нем позже с помощью:
Главное преимущество является то, что вам не нужно знать , сколько объекта экземпляров сохраняются для того , чтобы загрузить их позже (хотя это и без этой информации является возможным, требует немного специализированного кода). См. Ответы на связанный вопрос. Сохранение и загрузка нескольких объектов в файл pickle? для деталей о различных способах сделать это. Лично мне больше всего нравится ответ @Lutz Prechelt . Вот это адаптировано к примерам здесь:
источник
company1
иcompany2
. Почему бы вам не удалитьCompany
и не показать, что происходит?Я думаю, что это довольно сильное предположение, чтобы предположить, что объект является
class
. Что делать, если это неclass
? Есть также предположение, что объект не был определен в интерпретаторе. Что если это было определено в интерпретаторе? Кроме того, что если атрибуты были добавлены динамически? Когда некоторые объекты Python имеют атрибуты, добавленные к их__dict__
после создания,pickle
не учитывает добавление этих атрибутов (то есть он «забывает», что они были добавлены - потому чтоpickle
сериализуется с помощью ссылки на определение объекта).Во всех этих случаях вы
pickle
иcPickle
можете ужасно подвести вас.Если вы хотите сохранить
object
(произвольно созданный), где у вас есть атрибуты (добавленные в определении объекта или после) ... лучше всего использоватьdill
, который может сериализовать практически все в Python.Начнем с класса…
Теперь выключите и перезапустите ...
Ой ...
pickle
не могу справиться с этим. Давайте попробуемdill
. Мы добавим другой тип объекта (аlambda
) для хорошей меры.А теперь прочитайте файл.
Оно работает. Причиной
pickle
сбоя иdill
не является то, что онdill
обрабатывает__main__
как модуль (по большей части), а также может выбирать определения классов вместо выбора по ссылке (какpickle
делает). Причина, по которойdill
можно мариновать,lambda
состоит в том, что она дает ему имя ... тогда может произойти магия маринования.На самом деле, есть более простой способ сохранить все эти объекты, особенно если у вас есть много созданных вами объектов. Просто выкиньте весь сеанс Python и вернитесь к нему позже.
Теперь выключите компьютер, выпейте эспрессо или еще что-нибудь и зайдите позже ...
Единственным существенным недостатком является то, что
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
.Вы можете использовать anycache, чтобы сделать работу за вас. Он учитывает все детали:
pickle
модуль Python для обработкиlambda
и всех приятных возможностей Python.Предполагая, что у вас есть функция,
myfunc
которая создает экземпляр:Anycache звонки
myfunc
в первый раз и соленье результата в файл сcachedir
помощью уникального идентификатора ( в зависимости от имени функции и ее аргументов) в качестве имени файла. При любом последовательном прогоне засоленный объект загружается. Еслиcachedir
между запусками Python сохраняется, выбранный объект берется из предыдущего запуска Python.Для дальнейших подробностей смотрите документацию
источник
anycache
для сохранения более одного экземпляра, скажем,class
контейнера или, например, такогоlist
(который не был результатом вызова функции)?Быстрый пример использования
company1
из вашего вопроса, с python3.Однако, как отмечается в этом ответе , засолка часто дает сбой. Таким образом, вы должны действительно использовать
dill
.источник