Saya telah membuat objek seperti ini:
company1.name = 'banana'
company1.value = 40
Saya ingin menyimpan objek ini. Bagaimana saya bisa melakukan itu?
protocol=pickle.HIGHEST_PROTOCOL
. Jawaban saya juga memberi alternatif untuk acar.
Saya telah membuat objek seperti ini:
company1.name = 'banana'
company1.value = 40
Saya ingin menyimpan objek ini. Bagaimana saya bisa melakukan itu?
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:
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
Anda juga bisa mendefinisikan utilitas sederhana Anda sendiri seperti berikut ini yang membuka file dan menulis satu objek ke sana:
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')
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 daripada pickle
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 saja import
pernyataan ini:
import cPickle as pickle
Dalam Python 3, cPickle
diganti namanya _pickle
, tetapi melakukan ini tidak lagi diperlukan karena pickle
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:
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
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 Protokol 0
, tetapi dalam Python 3.8.1, itu adalah versi Protokol 4
. Dalam Python 3.x modul telah pickle.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:
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 Pickler
objek untuk digunakan dalam beberapa operasi acar:
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
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) .
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 dict
dan menulis semuanya ke file dalam satu panggilan:
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
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:
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
dan company2
. Mengapa Anda tidak juga menghapus Company
dan menunjukkan apa yang terjadi?
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, pickle
tidak menghormati penambahan atribut tersebut (yaitu 'lupa' mereka ditambahkan - karena pickle
serialisasi dengan mengacu pada definisi objek).
Dalam semua kasus ini, pickle
dan cPickle
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 menggunakan dill
, yang dapat membuat cerita bersambung hampir semua hal dalam python.
Kami mulai dengan kelas ...
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)
...
>>>
Sekarang tutup, dan mulai ulang ...
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'
>>>
Ups ... pickle
tidak bisa menanganinya. Ayo coba dill
. Kami akan melempar tipe objek lain (a lambda
) untuk ukuran yang baik.
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)
...
>>>
Dan sekarang baca file.
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
>>>
Berhasil. Alasannya pickle
gagal, dan dill
tidak, adalah bahwa dill
memperlakukan __main__
seperti modul (untuk sebagian besar), dan juga dapat acar definisi kelas daripada pengawetan dengan referensi (seperti pickle
halnya). Alasannya dill
bisa acar lambda
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.
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')
>>>
Sekarang matikan komputer Anda, nikmati espresso atau apa pun, dan kembali lagi nanti ...
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>
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
dengan git+https://github.com/uqfoundation/dill.git@master#egg=dill
. Dan Anda bisa mendapatkan versi rilis terbaru dengan pip install dill
.
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.
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 di dill
halaman github?
dill
masalah.
dil
Tapi aku memberiku MemoryError
! begitu juga cPickle
, pickle
dan hickle
.
Anda dapat menggunakan cache apa pun untuk melakukan pekerjaan untuk Anda. Itu mempertimbangkan semua detail:
pickle
modul python untuk menangani lambda
dan semua fitur python yang bagus.Dengan asumsi Anda memiliki fungsi myfunc
yang menciptakan instance:
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 memanggil myfunc
pada saat pertama dan mengambil hasilnya ke file dalam cachedir
menggunakan pengidentifikasi unik (tergantung pada nama fungsi dan argumennya) sebagai nama file. Pada proses yang berurutan, objek yang diambil akan dimuat. Jika cachedir
diawetkan antara menjalankan python, objek acar diambil dari jalankan python sebelumnya.
Untuk detail lebih lanjut lihat dokumentasi
anycache
untuk menyimpan lebih dari satu contoh dari, katakanlah, class
atau wadah seperti list
(itu bukan hasil dari memanggil fungsi)?
Contoh cepat menggunakan company1
dari 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"))