Karena ini adalah jawaban yang sangat populer, saya ingin menyentuh beberapa topik penggunaan yang agak canggih.
cPickle(atau _pickle) vs.pickle
Hampir selalu lebih disukai untuk benar-benar menggunakan cPicklemodul daripada picklekarena yang pertama ditulis dalam C dan jauh lebih cepat. Ada beberapa perbedaan kecil di antara mereka, tetapi dalam kebanyakan situasi mereka setara dan versi C akan memberikan kinerja yang sangat unggul. Beralih ke itu tidak bisa lebih mudah, ubah saja importpernyataan ini:
Rundown-nya adalah Anda bisa menggunakan sesuatu seperti berikut untuk memastikan bahwa kode Anda akan selalu menggunakan versi C saat tersedia di Python 2 dan 3:
try:import cPickle as pickleexceptModuleNotFoundError:import pickle
Format aliran data (protokol)
pickledapat membaca dan menulis file dalam beberapa format Python khusus, berbeda, yang disebut protokol seperti yang dijelaskan dalam dokumentasi , "Protokol versi 0" adalah ASCII dan karenanya "dapat dibaca manusia". Versi> 0 adalah biner dan yang tertinggi tersedia tergantung pada versi Python apa yang digunakan. Standarnya juga tergantung pada versi Python. Dalam Python 2 standarnya adalah versi Protokol 0, tetapi dalam Python 3.8.1, itu adalah versi Protokol 4. Dalam Python 3.x modul telah pickle.DEFAULT_PROTOCOLditambahkan ke dalamnya, tetapi itu tidak ada di Python 2.
Untungnya ada singkatan untuk menulis pickle.HIGHEST_PROTOCOLdi setiap panggilan (dengan asumsi itu yang Anda inginkan, dan biasanya Anda lakukan), cukup gunakan angka literal -1- mirip dengan merujuk elemen terakhir dari urutan melalui indeks negatif. Jadi, alih-alih menulis:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
Anda bisa menulis:
pickle.dump(obj, output,-1)
Bagaimanapun, Anda hanya perlu menentukan protokol sekali jika Anda membuat Picklerobjek untuk digunakan dalam beberapa operasi acar:
Catatan : Jika Anda berada di lingkungan yang menjalankan versi Python yang berbeda, maka Anda mungkin ingin menggunakan secara eksplisit (mis. Hardcode) nomor protokol khusus yang dapat dibaca oleh semuanya (versi selanjutnya umumnya dapat membaca file yang dihasilkan oleh yang sebelumnya) .
Banyak Objek
Sementara file acar dapat berisi sejumlah benda acar, seperti yang ditunjukkan dalam sampel di atas, ketika ada jumlah yang tidak diketahui dari mereka, itu sering lebih mudah untuk menyimpan mereka semua di semacam wadah bervariasi berukuran, seperti list, tuple, atau dictdan menulis semuanya ke file dalam satu panggilan:
dan pulihkan daftar dan semua yang ada di dalamnya nanti dengan:
with open('tech_companies.pkl','rb')as input:
tech_companies = pickle.load(input)
Keuntungan utama adalah Anda tidak perlu tahu berapa banyak instance objek yang disimpan untuk memuatnya kembali nanti (walaupun melakukannya tanpa informasi yang mungkin, diperlukan beberapa kode yang sedikit khusus). Lihat jawaban untuk pertanyaan terkait Menyimpan dan memuat beberapa objek dalam file acar? untuk perincian tentang berbagai cara untuk melakukan ini. Secara pribadi saya suka jawaban @Lutz Prechelt yang terbaik. Ini dia disesuaikan dengan contoh di sini:
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))
Ini langka bagi saya karena saya membayangkan akan ada cara yang lebih mudah untuk menyelamatkan suatu objek ... Sesuatu seperti 'saveobject (company1, c: \ mypythonobjects)
Peterstone
4
@Peterstone: Jika Anda hanya ingin menyimpan satu objek, Anda hanya perlu sekitar setengah dari kode pada contoh saya - Saya sengaja menulisnya seperti yang saya lakukan untuk menunjukkan bagaimana lebih dari satu objek dapat disimpan ke dalam (dan kemudian membaca kembali dari) file yang sama.
martineau
1
@Peterstone, ada alasan yang sangat bagus untuk pemisahan tanggung jawab. Dengan cara ini tidak ada batasan tentang bagaimana data dari proses pengawetan sedang digunakan. Anda dapat menyimpannya ke disk atau Anda juga dapat mengirimnya ke koneksi jaringan.
Harald Scheirich
3
@martinaeau, ini sebagai tanggapan terhadap komentar nada suara tentang seseorang yang seharusnya hanya memiliki satu fungsi untuk menyimpan objek ke disk. Tanggung jawab acar hanya untuk mengubah objek menjadi data yang dapat ditangani sebagai potongan. Menulis sesuatu ke file adalah tanggung jawab objek file. Dengan menjaga hal-hal yang terpisah satu memungkinkan penggunaan kembali yang lebih tinggi misalnya dapat mengirim data acar melintasi koneksi jaringan atau menyimpannya dalam database, semua tanggung jawab terpisah dari data aktual <-> konversi objek
Harald Scheirich
1
Anda menghapus company1dan company2. Mengapa Anda tidak juga menghapus Companydan menunjukkan apa yang terjadi?
Mike McKerns
49
Saya pikir itu asumsi yang cukup kuat untuk mengasumsikan bahwa objeknya adalah a class. Bagaimana jika itu bukan class? Ada juga anggapan bahwa objek tidak didefinisikan dalam interpreter. Bagaimana jika itu didefinisikan dalam interpreter? Juga, bagaimana jika atribut ditambahkan secara dinamis? Ketika beberapa objek python memiliki atribut yang ditambahkan ke __dict__setelah penciptaan mereka, pickletidak menghormati penambahan atribut tersebut (yaitu 'lupa' mereka ditambahkan - karena pickleserialisasi dengan mengacu pada definisi objek).
Dalam semua kasus ini, pickledan cPicklebisa mengecewakan Anda.
Jika Anda ingin menyimpan object(dibuat secara sewenang-wenang), di mana Anda memiliki atribut (baik ditambahkan dalam definisi objek, atau sesudahnya) ... taruhan terbaik Anda adalah menggunakan dill, yang dapat membuat cerita bersambung hampir semua hal dalam python.
Kami mulai dengan kelas ...
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)...>>>
Sekarang tutup, dan mulai ulang ...
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'>>>
Ups ... pickletidak bisa menanganinya. Ayo coba dill. Kami akan melempar tipe objek lain (a lambda) untuk ukuran yang baik.
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>>>
Berhasil. Alasannya picklegagal, dan dilltidak, adalah bahwa dillmemperlakukan __main__seperti modul (untuk sebagian besar), dan juga dapat acar definisi kelas daripada pengawetan dengan referensi (seperti picklehalnya). Alasannya dillbisa acar lambdaadalah karena memberi nama ... maka acar ajaib bisa terjadi.
Sebenarnya, ada cara yang lebih mudah untuk menyimpan semua objek ini, terutama jika Anda memiliki banyak objek yang Anda buat. Cukup buang seluruh sesi python, dan kembali lagi nanti.
Sekarang matikan komputer Anda, nikmati espresso atau apa pun, dan kembali lagi nanti ...
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>
Satu-satunya kelemahan utama adalah bahwa dillitu bukan bagian dari perpustakaan standar python. Jadi jika Anda tidak dapat menginstal paket python di server Anda, maka Anda tidak dapat menggunakannya.
Namun, jika Anda dapat menginstal paket python di sistem Anda, Anda bisa mendapatkan yang terbaru dilldengan git+https://github.com/uqfoundation/dill.git@master#egg=dill. Dan Anda bisa mendapatkan versi rilis terbaru dengan pip install dill.
Saya mendapatkan TypeError: __new__() takes at least 2 arguments (1 given)ketika mencoba menggunakan dill(yang terlihat menjanjikan) dengan objek yang agak rumit yang mencakup file audio.
MikeiLL
1
@ MikeikeL: Anda mendapatkan TypeErrorketika Anda melakukan apa, tepatnya? Itu biasanya tanda memiliki jumlah argumen yang salah ketika membuat instance kelas. Jika ini bukan bagian dari alur kerja dari pertanyaan di atas, dapatkah Anda mempostingnya sebagai pertanyaan lain, mengirimkannya kepada saya melalui email, atau menambahkannya sebagai masalah di dillhalaman github?
Mike McKerns
3
Bagi siapa pun yang mengikuti, berikut pertanyaan terkait @MikeLL yang diposkan - dari jawabannya, tampaknya bukan dillmasalah.
martineau
dilTapi aku memberiku MemoryError! begitu juga cPickle, pickledan hickle.
Färid Alijani
4
Anda dapat menggunakan cache apa pun untuk melakukan pekerjaan untuk Anda. Itu mempertimbangkan semua detail:
Menggunakan dill sebagai backend, yang memperluas picklemodul python untuk menangani lambdadan semua fitur python yang bagus.
Ini menyimpan objek yang berbeda ke file yang berbeda dan memuatnya dengan benar.
Membatasi ukuran cache
Mengizinkan pembersihan cache
Mengizinkan berbagi objek di antara beberapa proses
Mengizinkan penghormatan terhadap file input yang memengaruhi hasil
Dengan asumsi Anda memiliki fungsi myfuncyang menciptakan instance:
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 memanggil myfuncpada saat pertama dan mengambil hasilnya ke file dalam cachedirmenggunakan pengidentifikasi unik (tergantung pada nama fungsi dan argumennya) sebagai nama file. Pada proses yang berurutan, objek yang diambil akan dimuat. Jika cachedirdiawetkan antara menjalankan python, objek acar diambil dari jalankan python sebelumnya.
Bagaimana seseorang menggunakan anycacheuntuk menyimpan lebih dari satu contoh dari, katakanlah, classatau wadah seperti list(itu bukan hasil dari memanggil fungsi)?
martineau
2
Contoh cepat menggunakan company1dari pertanyaan Anda, dengan 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"))
Namun, seperti yang dicatat oleh jawaban ini , acar sering gagal. Jadi Anda harus benar-benar menggunakannya 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
. Jawaban saya juga memberi alternatif untuk acar.Jawaban:
Anda bisa menggunakan
pickle
modul di perpustakaan standar. Berikut ini adalah aplikasi dasar untuk contoh Anda:Anda juga bisa mendefinisikan utilitas sederhana Anda sendiri seperti berikut ini yang membuka file dan menulis satu objek ke sana:
Memperbarui
Karena ini adalah jawaban yang sangat populer, saya ingin menyentuh beberapa topik penggunaan yang agak canggih.
cPickle
(atau_pickle
) vs.pickle
Hampir selalu lebih disukai untuk benar-benar menggunakan
cPickle
modul daripadapickle
karena yang pertama ditulis dalam C dan jauh lebih cepat. Ada beberapa perbedaan kecil di antara mereka, tetapi dalam kebanyakan situasi mereka setara dan versi C akan memberikan kinerja yang sangat unggul. Beralih ke itu tidak bisa lebih mudah, ubah sajaimport
pernyataan ini:Dalam Python 3,
cPickle
diganti namanya_pickle
, tetapi melakukan ini tidak lagi diperlukan karenapickle
modul sekarang melakukannya secara otomatis — lihat Apa perbedaan antara acar dan _pickle dalam python 3? .Rundown-nya adalah Anda bisa menggunakan sesuatu seperti berikut untuk memastikan bahwa kode Anda akan selalu menggunakan versi C saat tersedia di Python 2 dan 3:
Format aliran data (protokol)
pickle
dapat membaca dan menulis file dalam beberapa format Python khusus, berbeda, yang disebut protokol seperti yang dijelaskan dalam dokumentasi , "Protokol versi 0" adalah ASCII dan karenanya "dapat dibaca manusia". Versi> 0 adalah biner dan yang tertinggi tersedia tergantung pada versi Python apa yang digunakan. Standarnya juga tergantung pada versi Python. Dalam Python 2 standarnya adalah versi Protokol0
, tetapi dalam Python 3.8.1, itu adalah versi Protokol4
. Dalam Python 3.x modul telahpickle.DEFAULT_PROTOCOL
ditambahkan ke dalamnya, tetapi itu tidak ada di Python 2.Untungnya ada singkatan untuk menulis
pickle.HIGHEST_PROTOCOL
di setiap panggilan (dengan asumsi itu yang Anda inginkan, dan biasanya Anda lakukan), cukup gunakan angka literal-1
- mirip dengan merujuk elemen terakhir dari urutan melalui indeks negatif. Jadi, alih-alih menulis:Anda bisa menulis:
Bagaimanapun, Anda hanya perlu menentukan protokol sekali jika Anda membuat
Pickler
objek untuk digunakan dalam beberapa operasi acar:Catatan : Jika Anda berada di lingkungan yang menjalankan versi Python yang berbeda, maka Anda mungkin ingin menggunakan secara eksplisit (mis. Hardcode) nomor protokol khusus yang dapat dibaca oleh semuanya (versi selanjutnya umumnya dapat membaca file yang dihasilkan oleh yang sebelumnya) .
Banyak Objek
Sementara file acar dapat berisi sejumlah benda acar, seperti yang ditunjukkan dalam sampel di atas, ketika ada jumlah yang tidak diketahui dari mereka, itu sering lebih mudah untuk menyimpan mereka semua di semacam wadah bervariasi berukuran, seperti
list
,tuple
, ataudict
dan menulis semuanya ke file dalam satu panggilan:dan pulihkan daftar dan semua yang ada di dalamnya nanti dengan:
Keuntungan utama adalah Anda tidak perlu tahu berapa banyak instance objek yang disimpan untuk memuatnya kembali nanti (walaupun melakukannya tanpa informasi yang mungkin, diperlukan beberapa kode yang sedikit khusus). Lihat jawaban untuk pertanyaan terkait Menyimpan dan memuat beberapa objek dalam file acar? untuk perincian tentang berbagai cara untuk melakukan ini. Secara pribadi saya suka jawaban @Lutz Prechelt yang terbaik. Ini dia disesuaikan dengan contoh di sini:
sumber
company1
dancompany2
. Mengapa Anda tidak juga menghapusCompany
dan menunjukkan apa yang terjadi?Saya pikir itu asumsi yang cukup kuat untuk mengasumsikan bahwa objeknya adalah a
class
. Bagaimana jika itu bukanclass
? Ada juga anggapan bahwa objek tidak didefinisikan dalam interpreter. Bagaimana jika itu didefinisikan dalam interpreter? Juga, bagaimana jika atribut ditambahkan secara dinamis? Ketika beberapa objek python memiliki atribut yang ditambahkan ke__dict__
setelah penciptaan mereka,pickle
tidak menghormati penambahan atribut tersebut (yaitu 'lupa' mereka ditambahkan - karenapickle
serialisasi dengan mengacu pada definisi objek).Dalam semua kasus ini,
pickle
dancPickle
bisa mengecewakan Anda.Jika Anda ingin menyimpan
object
(dibuat secara sewenang-wenang), di mana Anda memiliki atribut (baik ditambahkan dalam definisi objek, atau sesudahnya) ... taruhan terbaik Anda adalah menggunakandill
, yang dapat membuat cerita bersambung hampir semua hal dalam python.Kami mulai dengan kelas ...
Sekarang tutup, dan mulai ulang ...
Ups ...
pickle
tidak bisa menanganinya. Ayo cobadill
. Kami akan melempar tipe objek lain (alambda
) untuk ukuran yang baik.Dan sekarang baca file.
Berhasil. Alasannya
pickle
gagal, dandill
tidak, adalah bahwadill
memperlakukan__main__
seperti modul (untuk sebagian besar), dan juga dapat acar definisi kelas daripada pengawetan dengan referensi (sepertipickle
halnya). Alasannyadill
bisa acarlambda
adalah karena memberi nama ... maka acar ajaib bisa terjadi.Sebenarnya, ada cara yang lebih mudah untuk menyimpan semua objek ini, terutama jika Anda memiliki banyak objek yang Anda buat. Cukup buang seluruh sesi python, dan kembali lagi nanti.
Sekarang matikan komputer Anda, nikmati espresso atau apa pun, dan kembali lagi nanti ...
Satu-satunya kelemahan utama adalah bahwa
dill
itu bukan bagian dari perpustakaan standar python. Jadi jika Anda tidak dapat menginstal paket python di server Anda, maka Anda tidak dapat menggunakannya.Namun, jika Anda dapat menginstal paket python di sistem Anda, Anda bisa mendapatkan yang terbaru
dill
dengangit+https://github.com/uqfoundation/dill.git@master#egg=dill
. Dan Anda bisa mendapatkan versi rilis terbaru denganpip install dill
.sumber
TypeError: __new__() takes at least 2 arguments (1 given)
ketika mencoba menggunakandill
(yang terlihat menjanjikan) dengan objek yang agak rumit yang mencakup file audio.TypeError
ketika Anda melakukan apa, tepatnya? Itu biasanya tanda memiliki jumlah argumen yang salah ketika membuat instance kelas. Jika ini bukan bagian dari alur kerja dari pertanyaan di atas, dapatkah Anda mempostingnya sebagai pertanyaan lain, mengirimkannya kepada saya melalui email, atau menambahkannya sebagai masalah didill
halaman github?dill
masalah.dil
Tapi aku memberikuMemoryError
! begitu jugacPickle
,pickle
danhickle
.Anda dapat menggunakan cache apa pun untuk melakukan pekerjaan untuk Anda. Itu mempertimbangkan semua detail:
pickle
modul python untuk menanganilambda
dan semua fitur python yang bagus.Dengan asumsi Anda memiliki fungsi
myfunc
yang menciptakan instance:Anycache memanggil
myfunc
pada saat pertama dan mengambil hasilnya ke file dalamcachedir
menggunakan pengidentifikasi unik (tergantung pada nama fungsi dan argumennya) sebagai nama file. Pada proses yang berurutan, objek yang diambil akan dimuat. Jikacachedir
diawetkan antara menjalankan python, objek acar diambil dari jalankan python sebelumnya.Untuk detail lebih lanjut lihat dokumentasi
sumber
anycache
untuk menyimpan lebih dari satu contoh dari, katakanlah,class
atau wadah sepertilist
(itu bukan hasil dari memanggil fungsi)?Contoh cepat menggunakan
company1
dari pertanyaan Anda, dengan python3.Namun, seperti yang dicatat oleh jawaban ini , acar sering gagal. Jadi Anda harus benar-benar menggunakannya
dill
.sumber