Eu criei um objeto como este:
company1.name = 'banana'
company1.value = 40
Eu gostaria de salvar este objeto. Como eu posso fazer isso?
protocol=pickle.HIGHEST_PROTOCOL. Minha resposta também oferece alternativas para picles.
Eu criei um objeto como este:
company1.name = 'banana'
company1.value = 40
Eu gostaria de salvar este objeto. Como eu posso fazer isso?
protocol=pickle.HIGHEST_PROTOCOL. Minha resposta também oferece alternativas para picles.
Respostas:
Você pode usar o picklemódulo na biblioteca padrão. Aqui está uma aplicação elementar para o seu exemplo:
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
Você também pode definir seu próprio utilitário simples, como o seguinte, que abre um arquivo e grava um único objeto nele:
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')
Como essa é uma resposta tão popular, gostaria de abordar alguns tópicos de uso um pouco avançados.
cPickle(ou _pickle) vspickleÉ quase sempre preferível usar o cPicklemódulo, em vez de pickleporque o primeiro é escrito em C e é muito mais rápido. Existem algumas diferenças sutis entre eles, mas na maioria das situações eles são equivalentes e a versão C fornecerá um desempenho muito superior. Mudar para ele não poderia ser mais fácil, basta alterar a importdeclaração para isso:
import cPickle as pickle
No Python 3, cPicklefoi renomeado _pickle, mas isso não é mais necessário, já que o picklemódulo agora o faz automaticamente - consulte Que diferença entre pickle e _pickle no python 3? .
O resumo é que você pode usar algo como o seguinte para garantir que seu código sempre use a versão C quando estiver disponível no Python 2 e 3:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
picklepode ler e gravar arquivos em vários formatos diferentes, específicos para Python, chamados protocolos, conforme descrito na documentação , "Protocolo versão 0" é ASCII e, portanto, "legível por humanos". As versões> 0 são binárias e a mais alta disponível depende de qual versão do Python está sendo usada. O padrão também depende da versão do Python. No Python 2, o padrão era a versão Protocol 0, mas no Python 3.8.1, é a versão Protocol 4. No Python 3.x, o módulo foi pickle.DEFAULT_PROTOCOLadicionado, mas isso não existe no Python 2.
Felizmente, existe uma abreviação para escrever pickle.HIGHEST_PROTOCOLem todas as chamadas (assumindo que é isso que você deseja e costuma fazer), basta usar o número literal -1- semelhante a referenciar o último elemento de uma sequência por meio de um índice negativo. Então, em vez de escrever:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Você pode simplesmente escrever:
pickle.dump(obj, output, -1)
De qualquer forma, você só especificaria o protocolo uma vez se tivesse criado um Picklerobjeto para uso em várias operações de pickle:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
Nota : Se você estiver em um ambiente executando versões diferentes do Python, provavelmente desejará usar explicitamente (por exemplo, código rígido) um número de protocolo específico que todos possam ler (versões posteriores geralmente podem ler arquivos produzidos por versões anteriores) .
Enquanto um arquivo de picles pode conter qualquer número de objetos em conserva, como mostrado nas amostras acima, quando há um número desconhecido deles, muitas vezes é mais fácil de armazenar todos eles em algum tipo de recipiente de tamanho variável, como um list, tupleou dicte escrever todos eles para o arquivo em uma única chamada:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
e restaure a lista e tudo mais tarde com:
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
A principal vantagem é que você não precisa saber quantas instâncias de objetos são salvas para carregá-las novamente mais tarde (embora fazer isso sem essas informações seja possível, isso requer algum código um pouco especializado). Veja as respostas para a pergunta relacionada Salvando e carregando vários objetos no arquivo pickle? para obter detalhes sobre diferentes maneiras de fazer isso. Pessoalmente, eu gosto mais da resposta de @Lutz Prechelt . Aqui está adaptado aos exemplos aqui:
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))
company1e company2. Por que você também não exclui Companye mostra o que acontece?
Eu acho que é uma suposição bastante forte supor que o objeto é a class. E se não for um class? Há também a suposição de que o objeto não foi definido no intérprete. E se foi definido no intérprete? Além disso, e se os atributos fossem adicionados dinamicamente? Quando alguns objetos python têm atributos adicionados aos seus __dict__após a criação, picklenão respeita a adição desses atributos (ou seja, 'esquece' eles foram adicionados - porque pickleserializa por referência à definição do objeto).
Em todos esses casos, picklee cPicklepode falhar terrivelmente.
Se você deseja salvar um object(criado arbitrariamente), onde possui atributos (adicionados na definição do objeto ou posteriormente) ... sua melhor aposta é usar dill, que pode serializar quase tudo em python.
Começamos com uma aula…
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)
...
>>>
Agora desligue e reinicie ...
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'
>>>
Opa ... picklenão aguento. Vamos tentar dill. Vamos lançar outro tipo de objeto (a lambda) para uma boa medida.
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)
...
>>>
E agora leia o arquivo.
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
>>>
Funciona. A razão picklefalha, e dillnão, é que dilltrata __main__como um módulo (na maior parte), e também pode selecionar definições de classe em vez de selecionar por referência (como picklefaz). O motivo pelo qual dillum pickle lambdaé dado é que ele dá um nome ... então a magia do pickling pode acontecer.
Na verdade, há uma maneira mais fácil de salvar todos esses objetos, especialmente se você tiver muitos objetos criados. Apenas despeje a sessão inteira do python e volte mais tarde.
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')
>>>
Agora desligue o computador, desfrute de um café expresso ou o que quer que seja e volte mais tarde ...
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>
A única grande desvantagem é que dillnão faz parte da biblioteca padrão do python. Portanto, se você não pode instalar um pacote python no seu servidor, não pode usá-lo.
No entanto, se você conseguir instalar pacotes python no seu sistema, poderá obter as informações mais recentes dillcom git+https://github.com/uqfoundation/dill.git@master#egg=dill. E você pode obter a versão mais recente lançada com pip install dill.
TypeError: __new__() takes at least 2 arguments (1 given)ao tentar usar dill(o que parece promissor) com um objeto bastante complexo que inclui um arquivo de áudio.
TypeErrorquando faz o que, exatamente? Isso geralmente é um sinal de ter o número errado de argumentos ao instanciar uma instância de classe. Se isso não fizer parte do fluxo de trabalho da pergunta acima, você poderá publicá-la como outra pergunta, enviá-la por e-mail ou adicioná-la como um problema na dillpágina do github?
dillproblema.
dilEu me dou MemoryErrorembora! o mesmo acontece cPickle, picklee hickle.
Você pode usar o anycache para fazer o trabalho por você. Ele considera todos os detalhes:
picklemódulo python para lidar com lambdatodos os recursos legais do python.Supondo que você tenha uma função myfuncque cria a instância:
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)
O Anycache chama myfuncna primeira vez e seleciona o resultado em um arquivo cachedirusando um identificador exclusivo (dependendo do nome da função e de seus argumentos) como nome do arquivo. Em qualquer execução consecutiva, o objeto em conserva é carregado. Se o cachedirfor preservado entre execuções python, o objeto pickled será obtido da execução python anterior.
Para mais detalhes, consulte a documentação
anycachepara salvar mais de uma instância de, digamos, um classou contêiner como um list(que não foi o resultado da chamada de uma função)?
Exemplo rápido usando company1da sua pergunta, com 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"))
No entanto, como essa resposta observou, o pickle geralmente falha. Então você realmente deve usar 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"))