Serialisasi (serialization) adalah proses mengubah objek di dalam memori menjadi rangkaian byte yang dapat disimpan ke berkas atau dikirim antarproses, lalu dibangun kembali menjadi objek yang setara. Modul pickle adalah format serialisasi bawaan Python yang mampu menangani hampir seluruh tipe objek Python secara utuh. Topik ini membahas pemakaian pickle pada string byte dan berkas, batasannya dibandingkan JSON, serta catatan keamanan yang menyertainya.
Serialisasi dengan dumps dan loads#
Fungsi pickle.dumps() mengubah objek menjadi nilai bertipe bytes, dan fungsi pickle.loads() menguraikan byte tersebut kembali menjadi objek dengan struktur yang sama. Pasangan ini sering disebut roundtrip, karena objek keluar dan masuk kembali tanpa kehilangan bentuknya. Prosesnya berlaku pada struktur bersarang apa pun, termasuk dictionary yang berisi list di dalamnya.
import pickle
jadwal = {"Senin": ["Matematika", "Fisika"], "Selasa": ["Kimia", "Sejarah"]}
data = pickle.dumps(jadwal)
print(type(data).__name__)
hasil = pickle.loads(data)
print(hasil == jadwal)
print(hasil["Senin"][1])bytes
True
FisikaHasil dumps() berupa byte yang tidak dimaksudkan untuk dibaca manusia, dan pembandingan hasil == jadwal mengembalikan True karena isinya setara meskipun keduanya objek yang berbeda di memori. Keunggulan pickle terletak pada keutuhan tipe, yaitu dictionary tetap dictionary, kuncinya tetap bertipe aslinya, dan list di dalamnya tetap list. Untuk menyimpan dan membaca kembali, bentuk pickle.dump() dan pickle.load() bekerja langsung pada objek berkas tanpa melewati variabel byte terlebih dahulu.
Menyimpan objek ke berkas#
Berkas pickle ditulis dengan mode "wb" dan dibaca dengan mode "rb", karena isinya memang byte dan bukan teks. Akhiran .pkl yang lazim ditemui hanyalah konvensi penamaan, dan Python tidak menuntut akhiran tertentu. Pola pemakaiannya mirip penulisan berkas teks dengan open(), dengan perbedaan wajib pada pemilihan mode binernya.
import pickle
from pathlib import Path
with open("jadwal.pkl", "wb") as f:
pickle.dump({"Rabu": ["Biologi", "Olahraga"]}, f)
with open("jadwal.pkl", "rb") as f:
hasil = pickle.load(f)
print(hasil["Rabu"])
print("berkas tersimpan:", Path("jadwal.pkl").stat().st_size > 0)['Biologi', 'Olahraga']
berkas tersimpan: TruePemanggilan pickle.dump() menulis seluruh objek ke berkas dalam satu langkah, dan pickle.load() membacanya kembali menjadi objek yang utuh. Ukuran berkas diperiksa melalui stat().st_size sebagai konfirmasi sederhana bahwa berkas benar-benar berisi data. Pola ini tepat untuk cache antarproses, penyimpanan keadaan program, dan data sementara yang hanya dibaca kembali oleh Python.
Batasan pickle dan perbandingan dengan JSON#
Format pickle bersifat khusus Python, sedangkan JSON adalah format teks netral yang dapat dibaca hampir semua bahasa pemrograman. Perbedaan paling terlihat ada pada tipe kunci dictionary, karena JSON menuntut kunci berupa string, sedangkan pickle mempertahankan tipe aslinya. Perbedaan lain ada pada keutuhan tipe, dan contoh berikut membandingkan keduanya pada dictionary berkunci integer.
import json, pickle
data = {1: "satu", 2: "dua"}
kembali = json.loads(json.dumps(data))
print(type(next(iter(kembali))).__name__)
hasil = pickle.loads(pickle.dumps(data))
print(type(next(iter(hasil))).__name__)str
intJSON mengubah kunci 1 menjadi string '1', sedangkan pickle mengembalikannya sebagai integer seperti semula. Namun demikian, tidak semua objek dapat diserialisasi. Objek yang terikat pada keadaan luar seperti lambda, berkas yang sedang terbuka, dan koneksi jaringan ditolak oleh pickle karena tidak ada cara yang bermakna untuk membangunnya kembali.
import pickle
try:
pickle.dumps(lambda x: x + 1)
except Exception as e:
print(type(e).__name__)PicklingErrorSebagai pedoman praktis, JSON dipilih ketika data perlu dibaca sistem lain atau disimpan dalam jangka panjang, sedangkan pickle dipilih untuk data sementara yang masa pakainya seumur proyek Python yang sama. Pilihan ini mengikuti sifat keduanya, yaitu pickle utuh tetapi terikat pada Python, dan JSON terbatas tetapi netral.
Catatan keamanan pickle#
Proses pickle.loads() tidak sekadar membaca data, melainkan menjalankan instruksi untuk membangun objek apa pun yang tercantum di dalam byte-nya, termasuk memanggil fungsi dan metode tertentu. Berkas pickle dari sumber yang tidak dipercaya dengan demikian setara dengan program yang siap dijalankan, dan memuatnya berarti memberi izin kepada penulisnya untuk mengeksekusi kode pada mesin yang menjalankannya. Sifat inilah yang membedakan pickle dari JSON, karena penguraian JSON tidak pernah menjalankan kode apa pun.
Praktik yang aman adalah membatasi pickle untuk data yang dibuat dan dibaca kembali oleh program sendiri pada lingkungan yang dikuasai. Apabila berkas pickle harus bertahan lama, kehati-hatian tambahan diperlukan, karena perubahan definisi kelas antarversi dapat membuat objek lama tidak lagi cocok dengan kelas yang ada saat dibaca. Kasus semacam ini menjadi alasan tambahan untuk memilih format teks netral pada penyimpanan jangka panjang.
Kesalahan umum#
Kesalahan pertama adalah membuka berkas pickle dengan mode teks "r" alih-alih "rb". Byte biner ditafsirkan sebagai teks, dan proses pembacaannya berakhir dengan error dekode sebelum pickle sempat bekerja.
import pickle
with open("jadwal.pkl", "rb") as f:
print(pickle.load(f)["Rabu"])
try:
with open("jadwal.pkl", "r", encoding="utf-8") as f:
pickle.load(f)
except UnicodeDecodeError as e:
print(type(e).__name__)['Biologi', 'Olahraga']
UnicodeDecodeErrorKesalahan kedua adalah memakai pickle untuk data yang harus dibaca di luar Python. Berkasnya tidak dapat diuraikan oleh alat lain, sehingga aplikasi spreadsheet maupun bahasa pemrograman yang berbeda menolaknya. Kesalahan ketiga adalah menyimpan pickle sebagai arsip jangka panjang untuk objek berbasis kelas. Apabila definisi kelasnya berubah, berkas lama dapat gagal dimuat atau menghasilkan objek yang tidak lagi sesuai, sehingga arsip semacam ini lebih aman disimpan sebagai CSV atau JSON yang strukturnya eksplisit.
Ringkasan#
pickle.dumps()danpickle.loads()mengonversi objek menjadibytesdan sebaliknya, sedangkanpickle.dump()danpickle.load()bekerja langsung pada berkas mode biner.- Format pickle khusus Python dan mempertahankan tipe aslinya, sedangkan JSON bersifat teks netral dengan cakupan tipe yang lebih terbatas.
- Objek yang terikat pada keadaan luar, seperti lambda dan berkas terbuka, ditolak dengan
PicklingError. pickle.loads()dapat menjalankan kode arbitrer, sehingga berkas pickle hanya dimuat dari sumber yang dipercaya.
Referensi#
- pickle — Python object serialization — Python Software Foundation
— Referensi modul
pickle, termasuk peringatan keamanan resminya. - json — JSON encoder and decoder — Python Software Foundation — Alternatif serialisasi teks yang aman dibaca lintas bahasa.