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:
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 pickleexceptModuleNotFoundError:import pickle
Formatos de fluxo de dados (protocolos)
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:
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) .
Vários Objetos
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:
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:
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))
Isso é raro para mim, porque imaginei que haveria uma maneira mais fácil de salvar um objeto ... Algo como 'saveobject (company1, c: \ mypythonobjects) #
Peterstone
4
@ Peterstone: Se você apenas quisesse armazenar um objeto, precisaria apenas da metade do código que no meu exemplo - escrevi propositadamente da mesma maneira que fiz para mostrar como mais de um objeto pode ser salvo (e depois lido novamente de) o mesmo arquivo.
martineau
1
@ Peterstone, há uma boa razão para a separação de responsabilidades. Dessa forma, não há limitações quanto ao uso dos dados do processo de decapagem. Você pode armazená-lo em disco ou também pode enviá-lo através de uma conexão de rede.
Harald Scheirich
3
@martinaeau, isso foi em resposta a comentários perstones sobre um deve ter apenas uma função para salvar um objeto no disco. A responsabilidade do pickles é apenas transformar um objeto em dados que podem ser manipulados como um pedaço. Escrever coisas no arquivo é responsabilidade dos objetos do arquivo. Ao manter as coisas separadas uma possibilita maior reutilização por exemplo, ser capaz de enviar os dados em conserva accross uma conexão de rede ou armazená-lo em um banco de dados, todas as responsabilidades separar os dados reais <-> conversão objeto
Harald Scheirich
1
Você exclui company1e company2. Por que você também não exclui Companye mostra o que acontece?
Mike McKerns
49
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…
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)...>>>
Agora desligue e reinicie ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.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
returnUnpickler(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.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwin
Type"help","copyright","credits"or"license"for more information.>>>import dill
>>>classCompany:...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.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.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.
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.1((tags/Apple/clang-421.11.66))] on darwin
Type"help","copyright","credits"or"license"for more information.>>>import dill
>>>classCompany:...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 ...
Python2.7.8(default,Jul132014,02:29:54)[GCC 4.2.1CompatibleAppleClang4.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.
Estou recebendo um 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.
precisa saber é o seguinte
1
@ MikeiLL: Você está recebendo um 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?
Mike McKerns
3
Para quem acompanha, aqui está a pergunta relacionada @MikeLL postada - a partir da resposta, aparentemente não foi um dillproblema.
martineau
dilEu me dou MemoryErrorembora! o mesmo acontece cPickle, picklee hickle.
Färid Alijani 10/10
4
Você pode usar o anycache para fazer o trabalho por você. Ele considera todos os detalhes:
Ele usa dill como back-end, o que estende o picklemódulo python para lidar com lambdatodos os recursos legais do python.
Ele armazena objetos diferentes em arquivos diferentes e os recarrega adequadamente.
Limita o tamanho do cache
Permite limpeza de cache
Permite o compartilhamento de objetos entre várias execuções
Permite o respeito aos arquivos de entrada que influenciam o resultado
Supondo que você tenha uma função myfuncque cria a instância:
from anycache import anycache
classCompany(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)
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.
Como alguém usaria 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)?
martineau
2
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"))
protocol=pickle.HIGHEST_PROTOCOL
. Minha resposta também oferece alternativas para picles.Respostas:
Você pode usar o
pickle
módulo na biblioteca padrão. Aqui está uma aplicação elementar para o seu exemplo:Você também pode definir seu próprio utilitário simples, como o seguinte, que abre um arquivo e grava um único objeto nele:
Atualizar
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
cPickle
módulo, em vez depickle
porque 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 aimport
declaração para isso:No Python 3,
cPickle
foi renomeado_pickle
, mas isso não é mais necessário, já que opickle
mó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:
Formatos de fluxo de dados (protocolos)
pickle
pode 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 Protocol0
, mas no Python 3.8.1, é a versão Protocol4
. No Python 3.x, o módulo foipickle.DEFAULT_PROTOCOL
adicionado, mas isso não existe no Python 2.Felizmente, existe uma abreviação para escrever
pickle.HIGHEST_PROTOCOL
em 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:Você pode simplesmente escrever:
De qualquer forma, você só especificaria o protocolo uma vez se tivesse criado um
Pickler
objeto para uso em várias operações de pickle: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) .
Vários Objetos
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
,tuple
oudict
e escrever todos eles para o arquivo em uma única chamada:e restaure a lista e tudo mais tarde com:
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:
fonte
company1
ecompany2
. Por que você também não excluiCompany
e mostra o que acontece?Eu acho que é uma suposição bastante forte supor que o objeto é a
class
. E se não for umclass
? 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,pickle
não respeita a adição desses atributos (ou seja, 'esquece' eles foram adicionados - porquepickle
serializa por referência à definição do objeto).Em todos esses casos,
pickle
ecPickle
pode falhar terrivelmente.Se você deseja salvar um
object
(criado arbitrariamente), onde possui atributos (adicionados na definição do objeto ou posteriormente) ... sua melhor aposta é usardill
, que pode serializar quase tudo em python.Começamos com uma aula…
Agora desligue e reinicie ...
Opa ...
pickle
não aguento. Vamos tentardill
. Vamos lançar outro tipo de objeto (alambda
) para uma boa medida.E agora leia o arquivo.
Funciona. A razão
pickle
falha, edill
não, é quedill
trata__main__
como um módulo (na maior parte), e também pode selecionar definições de classe em vez de selecionar por referência (comopickle
faz). O motivo pelo qualdill
um picklelambda
é 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.
Agora desligue o computador, desfrute de um café expresso ou o que quer que seja e volte mais tarde ...
A única grande desvantagem é que
dill
nã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
dill
comgit+https://github.com/uqfoundation/dill.git@master#egg=dill
. E você pode obter a versão mais recente lançada compip install dill
.fonte
TypeError: __new__() takes at least 2 arguments (1 given)
ao tentar usardill
(o que parece promissor) com um objeto bastante complexo que inclui um arquivo de áudio.TypeError
quando 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 nadill
página do github?dill
problema.dil
Eu me douMemoryError
embora! o mesmo acontececPickle
,pickle
ehickle
.Você pode usar o anycache para fazer o trabalho por você. Ele considera todos os detalhes:
pickle
módulo python para lidar comlambda
todos os recursos legais do python.Supondo que você tenha uma função
myfunc
que cria a instância:O Anycache chama
myfunc
na primeira vez e seleciona o resultado em um arquivocachedir
usando 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 ocachedir
for preservado entre execuções python, o objeto pickled será obtido da execução python anterior.Para mais detalhes, consulte a documentação
fonte
anycache
para salvar mais de uma instância de, digamos, umclass
ou contêiner como umlist
(que não foi o resultado da chamada de uma função)?Exemplo rápido usando
company1
da sua pergunta, com python3.No entanto, como essa resposta observou, o pickle geralmente falha. Então você realmente deve usar
dill
.fonte