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 picklemodul 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.pickleHampir 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:
import cPickle as pickle
Dalam Python 3, cPicklediganti namanya _pickle, tetapi melakukan ini tidak lagi diperlukan karena picklemodul 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
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:
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 dictdan 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))
company1dan company2. Mengapa Anda tidak juga menghapus Companydan 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, 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 ...
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 ... pickletidak 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 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.
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 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.
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.
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?
dillmasalah.
dilTapi aku memberiku MemoryError! begitu juga cPickle, pickledan hickle.
Anda dapat menggunakan cache apa pun untuk melakukan pekerjaan untuk Anda. Itu mempertimbangkan semua detail:
picklemodul python untuk menangani lambdadan semua fitur python yang bagus.Dengan asumsi Anda memiliki fungsi myfuncyang 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 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.
Untuk detail lebih lanjut lihat dokumentasi
anycacheuntuk menyimpan lebih dari satu contoh dari, katakanlah, classatau wadah seperti list(itu bukan hasil dari memanggil fungsi)?
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"))