Tulis program berbasis menu dengan Python yang meminta pengguna untuk menambah, menampilkan, dan mencari catatan karyawan yang disimpan dalam file biner. Catatan karyawan berisi kode karyawan, nama dan gaji. Itu harus disimpan dalam objek daftar. Program Anda harus mengambil objek dan menyimpannya ke file biner
Serialisasi (Juga disebut Pickling). Proses mengubah hierarki objek Python menjadi aliran byte sehingga dapat ditulis ke dalam file
De-Serialisasi (Juga disebut Unpickling). Kebalikan dari Pickling di mana aliran byte diubah menjadi hierarki objek. Unpickling menghasilkan salinan yang tepat dari objek asli
- Modul acar impor pertama
- Gunakan metode dump() dan load() dari modul pickle untuk melakukan operasi baca dan tulis pada file biner
Mode Pembukaan File
tulisan wb saja. Menimpa file biner jika ada. Jika tidak, buat file biner baru untuk ditulis
wb+ baik menulis maupun membaca. Menimpa file biner jika ada. Jika tidak, buat file biner baru untuk ditulis
rb hanya membaca. Menetapkan penunjuk file di awal file biner
rb+ baik membaca maupun menulis. Menetapkan penunjuk file di awal file biner
ab untuk menambahkan. Pindahkan penunjuk file di akhir file biner. Membuat file baru untuk menulis, jika tidak ada
ab+ untuk menambahkan dan membaca. Pindahkan penunjuk file di akhir. Jika file biner tidak ada, itu membuat file baru untuk membaca dan menulis
- Menulis ke File Biner. Pengawetan
Keluaran
2. Tulis program untuk membuka file EMP. dat(Dibuat di program sebelumnya), baca objek yang tertulis di dalamnya dan tampilkan
Keluaran
3. Tulis program untuk menambahkan dua catatan karyawan ke file yang dibuat di program sebelumnya dengan mendapatkan data dari pengguna
Keluaran
Mengakses dan memanipulasi lokasi penunjuk file
Python menyediakan dua fungsi untuk memanipulasi posisi pointer file dan dengan demikian pengguna dapat membaca dan menulis dari posisi yang diinginkan
Fungsi beri tahu ( ).
Fungsi tell() mengembalikan posisi penunjuk file saat ini di dalam file
. memberi tahu( )
Fungsi mencari ( ).
Fungsi seek ( ) mengubah posisi penunjuk file dengan menempatkan penunjuk file pada posisi yang ditentukan dalam file terbuka
. mencari(offset[,mode])
Di mana
offset =======>adalah angka yang menentukan jumlah byte
modus =======> adalah angka 0 atau 1 atau 2
0 untuk awal file
1 posisi penunjuk file saat ini
2 akhir file
4. Tulis program untuk membuka file EMP. dat(Dibuat di program sebelumnya), baca dan ubah nama empno1207 menjadi vijay7 baru dan tampilkan
Modul mengimplementasikan protokol biner untuk serialisasi dan de-serialisasi struktur objek Python. "Pickling" adalah proses di mana hierarki objek Python diubah menjadi aliran byte, dan "unpickling" adalah operasi kebalikannya, di mana aliran byte (dari a atau ) diubah kembali menjadi hierarki objek. Pengawetan (dan penghilangan pengawetan) secara alternatif dikenal sebagai "serialisasi", "penataan", atau "perataan";
Peringatan
Modul def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 7 tidak aman. Hapus hanya data yang Anda percayai
Dimungkinkan untuk membangun data acar berbahaya yang akan mengeksekusi kode arbitrer selama unpickling. Jangan pernah membongkar data yang mungkin berasal dari sumber yang tidak tepercaya, atau yang mungkin telah dirusak
Pertimbangkan untuk menandatangani data dengan jika Anda perlu memastikan bahwa itu belum dirusak
Format serialisasi yang lebih aman seperti mungkin lebih sesuai jika Anda memproses data yang tidak tepercaya. Melihat
Hubungan dengan modul Python lainnya
Perbandingan dengan # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _2
Python memiliki modul serialisasi yang lebih primitif yang disebut , tetapi secara umum harus selalu menjadi cara yang disukai untuk membuat serialisasi objek Python. ada terutama untuk mendukung file # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _6 Python
Modul ini berbeda dari beberapa cara yang signifikan
Modul melacak objek yang telah diserialkan, sehingga referensi selanjutnya ke objek yang sama tidak akan diserialkan lagi. tidak melakukan ini
Ini memiliki implikasi baik untuk objek rekursif dan berbagi objek. Objek rekursif adalah objek yang berisi referensi ke dirinya sendiri. Ini tidak ditangani oleh marshal, dan pada kenyataannya, mencoba menyusun objek rekursif akan membuat juru bahasa Python Anda crash. Berbagi objek terjadi ketika ada beberapa referensi ke objek yang sama di tempat yang berbeda dalam hierarki objek yang diserialisasi. menyimpan objek semacam itu hanya sekali, dan memastikan bahwa semua referensi lainnya mengarah ke salinan master. Objek yang dibagikan tetap dibagikan, yang bisa sangat penting untuk objek yang bisa berubah
tidak dapat digunakan untuk membuat serialisasi kelas yang ditentukan pengguna dan instansnya. dapat menyimpan dan memulihkan instance kelas secara transparan, namun definisi kelas harus dapat diimpor dan berada dalam modul yang sama seperti saat objek disimpan
Format serialisasi tidak dijamin portabel di seluruh versi Python. Karena tugas utamanya dalam hidup adalah untuk mendukung # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _6 file, pelaksana Python berhak untuk mengubah format serialisasi dengan cara yang tidak kompatibel mundur jika diperlukan. Format serialisasi dijamin kompatibel ke belakang di seluruh rilis Python asalkan protokol acar yang kompatibel dipilih dan kode pickling dan unpickling berurusan dengan perbedaan jenis Python 2 ke Python 3 jika data Anda melintasi batas bahasa perubahan yang unik itu
Perbandingan dengan # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _1
Ada perbedaan mendasar antara protokol pickle dan JSON (JavaScript Object Notation)
JSON adalah format serialisasi teks (menghasilkan teks unicode, meskipun sebagian besar waktu kemudian dikodekan ke f = io.BytesIO() p = pickle.Pickler(f) p.dispatch_table = copyreg.dispatch_table.copy() p.dispatch_table[SomeClass] = reduce_SomeClass 8), sedangkan pickle adalah format serialisasi biner;
JSON dapat dibaca manusia, sedangkan acar tidak;
JSON dapat dioperasikan dan banyak digunakan di luar ekosistem Python, sedangkan pickle khusus untuk Python;
JSON, secara default, hanya dapat mewakili subset dari tipe bawaan Python, dan tidak ada kelas khusus;
Tidak seperti pickle, deserializing JSON yang tidak dipercaya tidak dengan sendirinya menciptakan kerentanan eksekusi kode arbitrer
Lihat juga
Modul. modul pustaka standar yang memungkinkan serialisasi dan deserialisasi JSON
Format aliran data
Format data yang digunakan oleh khusus untuk Python. Ini memiliki keuntungan bahwa tidak ada batasan yang diberlakukan oleh standar eksternal seperti JSON atau XDR (yang tidak dapat mewakili berbagi pointer);
Secara default, format data menggunakan representasi biner yang relatif ringkas. Jika Anda membutuhkan karakteristik ukuran yang optimal, Anda dapat mengompres data acar secara efisien.
Modul berisi alat untuk menganalisis aliran data yang dihasilkan oleh. kode sumber memiliki komentar ekstensif tentang opcode yang digunakan oleh protokol acar
Saat ini ada 6 protokol berbeda yang dapat digunakan untuk pengawetan. Semakin tinggi protokol yang digunakan, semakin baru versi Python yang dibutuhkan untuk membaca acar yang dihasilkan
Protokol versi 0 adalah protokol asli "yang dapat dibaca manusia" dan kompatibel dengan versi sebelumnya dari Python
Protokol versi 1 adalah format biner lama yang juga kompatibel dengan versi Python sebelumnya
Protokol versi 2 diperkenalkan dengan Python 2. 3. Ini memberikan pengawetan yang jauh lebih efisien. Lihat PEP 307 untuk informasi tentang peningkatan yang dibawa oleh protokol 2
Protokol versi 3 ditambahkan di Python 3. 0. Ini memiliki dukungan eksplisit untuk objek dan tidak dapat dihapus oleh Python 2. x. Ini adalah protokol default di Python 3. 0–3. 7
Protokol versi 4 ditambahkan di Python 3. 4. Itu menambahkan dukungan untuk objek yang sangat besar, memilih lebih banyak jenis objek, dan beberapa pengoptimalan format data. Ini adalah protokol default yang dimulai dengan Python 3. 8. Lihat PEP 3154 untuk informasi tentang peningkatan yang dibawa oleh protokol 4
Protokol versi 5 ditambahkan di Python 3. 8. Itu menambahkan dukungan untuk data out-of-band dan speedup untuk data in-band. Lihat PEP 574 untuk informasi tentang peningkatan yang dibawa oleh protokol 5
Catatan
Serialisasi adalah gagasan yang lebih primitif daripada kegigihan; . Modul dapat mengubah objek kompleks menjadi aliran byte dan dapat mengubah aliran byte menjadi objek dengan struktur internal yang sama. Mungkin hal yang paling jelas untuk dilakukan dengan aliran byte ini adalah menuliskannya ke file, tetapi juga memungkinkan untuk mengirimnya melalui jaringan atau menyimpannya dalam database. Modul ini menyediakan antarmuka sederhana untuk memilih dan memisahkan objek pada file database bergaya DBM
Antarmuka Modul
Untuk membuat serial hierarki objek, Anda cukup memanggil fungsi. Demikian pula, untuk membatalkan serial aliran data, Anda memanggil fungsi tersebut. Namun, jika Anda ingin lebih mengontrol serialisasi dan de-serialisasi, Anda dapat membuat objek masing-masing
Modul ini menyediakan konstanta berikut
acar. HIGHEST_PROTOCOLBilangan bulat, tertinggi yang tersedia. Nilai ini dapat diteruskan sebagai nilai protokol ke fungsi dan juga konstruktor
acar. DEFAULT_PROTOCOLBilangan bulat, standar yang digunakan untuk pengawetan. Mungkin kurang dari. Saat ini protokol defaultnya adalah 4, pertama kali diperkenalkan di Python 3. 4 dan tidak kompatibel dengan versi sebelumnya
Berubah di versi 3. 0. Protokol defaultnya adalah 3.
Berubah di versi 3. 8. Protokol standarnya adalah 4.
Modul ini menyediakan fungsi-fungsi berikut untuk mempermudah proses pengawetan
acar. dump(obj , berkas, protocol=None, *, fix_imports=True, buffer_callback=None)Tulis representasi acar dari objek obj ke file yang terbuka. Ini setara dengan copyreg.pickle(SomeClass, reduce_SomeClass) f = io.BytesIO() p = pickle.Pickler(f) _9
File argumen, protokol, fix_imports dan buffer_callback memiliki arti yang sama seperti pada konstruktor
Berubah di versi 3. 8. Argumen buffer_callback telah ditambahkan.
acar. dumps(obj , protokol=None, *, fix_imports=True, buffer_callback=None)Kembalikan representasi acar dari objek obj sebagai objek, alih-alih menulisnya ke file
Protokol argumen, fix_imports dan buffer_callback memiliki arti yang sama seperti pada konstruktor
Berubah di versi 3. 8. Argumen buffer_callback telah ditambahkan.
acar. muat(file , *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)Baca representasi acar dari suatu objek dari file yang terbuka dan kembalikan hierarki objek yang dibentuk kembali yang ditentukan di dalamnya. Ini setara dengan class TextReader: """Print and number lines in a text file.""" def __init__(self, filename): self.filename = filename self.file = open(filename) self.lineno = 0 def readline(self): self.lineno += 1 line = self.file.readline() if not line: return None if line.endswith('\n'): line = line[:-1] return "%i: %s" % (self.lineno, line) def __getstate__(self): # Copy the object's state from self.__dict__ which contains # all our instance attributes. Always use the dict.copy() # method to avoid modifying the original state. state = self.__dict__.copy() # Remove the unpicklable entries. del state['file'] return state def __setstate__(self, state): # Restore instance attributes (i.e., filename and lineno). self.__dict__.update(state) # Restore the previously opened file's state. To do so, we need to # reopen it and read from it until the line count is restored. file = open(self.filename) for _ in range(self.lineno): file.readline() # Finally, save the file. self.file = file _3
Versi protokol acar terdeteksi secara otomatis, jadi tidak diperlukan argumen protokol. Byte yang melewati representasi acar dari objek akan diabaikan
File argumen, fix_imports, encoding, error, strict dan buffer memiliki arti yang sama seperti pada konstruktor
Berubah di versi 3. 8. Argumen penyangga telah ditambahkan.
acar. memuat(data , /, *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)Kembalikan hierarki objek yang dibentuk kembali dari data representasi acar dari suatu objek. data harus a
Versi protokol acar terdeteksi secara otomatis, jadi tidak diperlukan argumen protokol. Byte yang melewati representasi acar dari objek akan diabaikan
Argumen fix_imports, encoding, error, strict dan buffer memiliki arti yang sama seperti pada konstruktor
Berubah di versi 3. 8. Argumen penyangga telah ditambahkan.
Modul ini mendefinisikan tiga pengecualian
pengecualian acar. PickleErrorKelas dasar umum untuk pengecualian pengawetan lainnya. Itu mewarisi
pengecualian acar. PicklingErrorKesalahan muncul saat objek yang tidak dapat diambil ditemukan oleh. Itu mewarisi
Lihat untuk mempelajari jenis benda apa yang bisa diasinkan
pengecualian acar. UnpicklingErrorKesalahan muncul saat ada masalah saat membongkar objek, seperti kerusakan data atau pelanggaran keamanan. Itu mewarisi
Perhatikan bahwa pengecualian lain juga dapat dimunculkan selama unpickling, termasuk (namun tidak terbatas pada) AttributeError, EOFError, ImportError, dan IndexError
Modul mengekspor tiga kelas, , dan
kelas acar. Pickler(file , protokol=None, *, fix_imports=True, buffer_callback=None)Ini membutuhkan file biner untuk menulis aliran data acar
Argumen protokol opsional, bilangan bulat, memberi tahu pickler untuk menggunakan protokol yang diberikan; . Jika tidak ditentukan, defaultnya adalah. Jika angka negatif ditentukan, dipilih
Argumen file harus memiliki metode write() yang menerima argumen byte tunggal. Dengan demikian dapat berupa file on-disk yang dibuka untuk penulisan biner, instance, atau objek khusus lainnya yang memenuhi antarmuka ini
Jika fix_imports benar dan protokol kurang dari 3, acar akan mencoba memetakan nama Python 3 baru ke nama modul lama yang digunakan dalam Python 2, sehingga aliran data acar dapat dibaca dengan Python 2
Jika buffer_callback adalah Tidak Ada (default), tampilan buffer diserialkan ke dalam file sebagai bagian dari aliran acar
Jika buffer_callback bukan Tidak ada, maka dapat dipanggil beberapa kali dengan tampilan buffer. Jika callback mengembalikan nilai false (seperti Tidak ada), buffer yang diberikan adalah ; . e. di dalam aliran acar
Ini adalah kesalahan jika buffer_callback bukan Tidak Ada dan protokol Tidak ada atau lebih kecil dari 5
Berubah di versi 3. 8. Argumen buffer_callback telah ditambahkan.
dump(obj)Tulis representasi acar dari objek ke objek file terbuka yang diberikan dalam konstruktor
persistent_id(obj)Tidak melakukan apa pun secara default. Ini ada sehingga subkelas dapat menimpanya
Jika mengembalikan import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 _0, obj diasamkan seperti biasa. Nilai lain apa pun menyebabkan memancarkan nilai yang dikembalikan sebagai ID persisten untuk objek. Arti dari ID persisten ini harus ditentukan oleh. Perhatikan bahwa nilai yang dikembalikan oleh itu sendiri tidak dapat memiliki ID persisten
Lihat detail dan contoh penggunaan
dispatch_tableTabel pengiriman objek pickler adalah daftar fungsi reduksi dari jenis yang dapat dideklarasikan menggunakan. Ini adalah pemetaan yang kuncinya adalah kelas dan nilainya adalah fungsi reduksi. Fungsi reduksi mengambil satu argumen dari kelas terkait dan harus sesuai dengan antarmuka yang sama dengan metode import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 5
Secara default, objek pickler tidak akan memiliki atribut, dan akan menggunakan tabel pengiriman global yang dikelola oleh modul. Namun, untuk menyesuaikan pengawetan untuk objek pickler tertentu, seseorang dapat mengatur atributnya ke objek seperti dict. Alternatifnya, jika subkelas dari memiliki atribut maka ini akan digunakan sebagai tabel pengiriman default untuk instance dari kelas tersebut
Lihat untuk contoh penggunaan
Baru di versi 3. 3
reducer_override(obj)Reducer khusus yang dapat didefinisikan dalam subclass. Metode ini diprioritaskan daripada peredam apa pun di. Itu harus sesuai dengan antarmuka yang sama dengan metode import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 5, dan secara opsional dapat mengembalikan class ZeroCopyByteArray(bytearray): def __reduce_ex__(self, protocol): if protocol >= 5: return type(self)._reconstruct, (PickleBuffer(self),), None else: # PickleBuffer is forbidden with pickle protocols <= 4. return type(self)._reconstruct, (bytearray(self),) @classmethod def _reconstruct(cls, obj): with memoryview(obj) as m: # Get a handle over the original buffer object obj = m.obj if type(obj) is cls: # Original buffer object is a ZeroCopyByteArray, return it # as-is. return obj else: return cls(obj) 4 untuk mundur pada reduksi terdaftar - ke acar class ZeroCopyByteArray(bytearray): def __reduce_ex__(self, protocol): if protocol >= 5: return type(self)._reconstruct, (PickleBuffer(self),), None else: # PickleBuffer is forbidden with pickle protocols <= 4. return type(self)._reconstruct, (bytearray(self),) @classmethod def _reconstruct(cls, obj): with memoryview(obj) as m: # Get a handle over the original buffer object obj = m.obj if type(obj) is cls: # Original buffer object is a ZeroCopyByteArray, return it # as-is. return obj else: return cls(obj) 6
Untuk contoh terperinci, lihat
Baru di versi 3. 8
cepatTidak digunakan lagi. Aktifkan mode cepat jika disetel ke nilai sebenarnya. Mode cepat menonaktifkan penggunaan memo, sehingga mempercepat proses pengawetan dengan tidak menghasilkan opcode PUT yang berlebihan. Itu tidak boleh digunakan dengan objek referensi diri, melakukan sebaliknya akan menyebabkan berulang tanpa batas
Gunakan jika Anda membutuhkan acar yang lebih padat
kelas acar. Unpickler(file , *, fix_imports=True, encoding='ASCII', errors='strict', buffers=None)Ini membutuhkan file biner untuk membaca aliran data acar
Versi protokol acar terdeteksi secara otomatis, jadi tidak diperlukan argumen protokol
File argumen harus memiliki tiga metode, metode read() yang mengambil argumen bilangan bulat, metode readinto() yang mengambil argumen buffer, dan metode readline() yang tidak memerlukan argumen, seperti pada antarmuka. Dengan demikian file dapat berupa file on-disk yang dibuka untuk pembacaan biner, objek, atau objek khusus lainnya yang memenuhi antarmuka ini
Argumen opsional fix_imports, encoding dan error digunakan untuk mengontrol dukungan kompatibilitas untuk aliran acar yang dihasilkan oleh Python 2. Jika fix_imports benar, acar akan mencoba memetakan nama Python 2 lama ke nama baru yang digunakan di Python 3. Pengodean dan kesalahan memberi tahu pickle cara mendekode instance string 8-bit yang diasinkan oleh Python 2; . Pengkodean dapat berupa 'byte' untuk membaca instance string 8-bit ini sebagai objek byte. Menggunakan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _01 diperlukan untuk menghapus array NumPy dan instance dari , dan diasamkan oleh Python 2
Jika buffer adalah Tidak Ada (default), maka semua data yang diperlukan untuk deserialisasi harus dimuat dalam aliran acar. Ini berarti bahwa argumen buffer_callback adalah Tidak ada saat a dipakai (atau saat atau dipanggil)
Jika buffer bukan Tidak ada, itu harus merupakan iterable dari objek berkemampuan buffer yang dikonsumsi setiap kali aliran acar mereferensikan tampilan buffer. Buffer tersebut telah diberikan untuk buffer_callback dari objek Pickler
Berubah di versi 3. 8. Argumen penyangga telah ditambahkan.
memuat()Baca representasi acar dari suatu objek dari objek file terbuka yang diberikan dalam konstruktor, dan kembalikan hierarki objek yang dibentuk kembali yang ditentukan di dalamnya. Byte yang melewati representasi acar dari objek akan diabaikan
persistent_load(pid)Naikkan secara default
Jika ditentukan, harus mengembalikan objek yang ditentukan oleh pid ID persisten. Jika ditemukan ID persisten yang tidak valid, an harus dinaikkan
Lihat detail dan contoh penggunaan
find_class(modul , nama)Impor modul jika perlu dan kembalikan objek yang disebut nama darinya, di mana argumen modul dan nama adalah objek. Perhatikan, tidak seperti namanya, ini juga digunakan untuk menemukan fungsi
Subclass dapat mengesampingkan ini untuk mendapatkan kontrol atas jenis objek apa dan bagaimana mereka dapat dimuat, berpotensi mengurangi risiko keamanan. Lihat untuk detailnya
Memunculkan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 13 dengan argumen def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 14, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 15
Pembungkus untuk buffer yang mewakili data picklable. buffer harus berupa objek, seperti array berdimensi atau N
sendiri merupakan penyedia buffer, oleh karena itu dimungkinkan untuk meneruskannya ke API lain yang mengharapkan objek penyedia buffer, seperti
objek hanya dapat diserialisasi menggunakan protokol acar 5 atau lebih tinggi. Mereka memenuhi syarat untuk
Baru di versi 3. 8
mentah()Kembalikan a dari area memori yang mendasari buffer ini. Objek yang dikembalikan adalah tampilan memori C-contiguous satu dimensi dengan format def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 20 (unsigned byte). dinaikkan jika buffer tidak bersebelahan dengan C- atau Fortran
rilis()Lepaskan buffer dasar yang diekspos oleh objek PickleBuffer
Apa yang bisa diasinkan dan tidak diasamkan?
Jenis-jenis berikut dapat diasinkan
import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 0, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 23, dan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 24;
bilangan bulat, bilangan floating-point, bilangan kompleks;
string, byte, bytearray;
tupel, daftar, set, dan kamus yang hanya berisi objek yang dapat dipilih;
fungsi (bawaan dan ditentukan pengguna) dapat diakses dari tingkat atas modul (menggunakan , bukan );
kelas dapat diakses dari tingkat atas modul;
contoh dari kelas-kelas tersebut yang hasil pemanggilannya def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 27 dapat dipilih (lihat bagian untuk detailnya)
Upaya untuk mengasinkan objek yang tidak dapat diawetkan akan menimbulkan pengecualian; . Mencoba memilih struktur data yang sangat rekursif dapat melebihi kedalaman rekursi maksimum, a akan dimunculkan dalam kasus ini. Anda dapat dengan hati-hati menaikkan batas ini dengan
Perhatikan bahwa fungsi (bawaan dan ditentukan pengguna) diasamkan oleh fully , bukan berdasarkan nilai. Ini berarti bahwa hanya nama fungsi yang diasamkan, bersama dengan nama modul dan kelas yang memuatnya. Baik kode fungsi, maupun atribut fungsinya tidak diasamkan. Jadi modul pendefinisian harus dapat diimpor di lingkungan unpickling, dan modul harus berisi objek bernama, jika tidak, pengecualian akan dimunculkan.
Demikian pula, kelas diasamkan dengan nama yang memenuhi syarat, jadi batasan yang sama di lingkungan unpickling berlaku. Perhatikan bahwa tidak ada kode atau data kelas yang diasamkan, jadi dalam contoh berikut atribut kelas def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 31 tidak dipulihkan di lingkungan unpickling
class Foo: attr = 'A class attribute' picklestring = pickle.dumps(Foo)
Pembatasan ini adalah mengapa fungsi dan kelas picklable harus didefinisikan di tingkat atas modul
Demikian pula, ketika instance kelas diasamkan, kode dan data kelasnya tidak diasamkan bersama mereka. Hanya data instance yang diasamkan. Ini dilakukan dengan sengaja, sehingga Anda dapat memperbaiki bug di kelas atau menambahkan metode ke kelas dan tetap memuat objek yang dibuat dengan versi kelas sebelumnya. Jika Anda berencana untuk memiliki objek berumur panjang yang akan melihat banyak versi kelas, mungkin bermanfaat untuk memasukkan nomor versi ke dalam objek sehingga konversi yang sesuai dapat dilakukan dengan metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 32 kelas
Contoh Kelas Pengawetan
Di bagian ini, kami menjelaskan mekanisme umum yang tersedia bagi Anda untuk mendefinisikan, menyesuaikan, dan mengontrol bagaimana instance kelas dipilih dan dipisahkan
Dalam kebanyakan kasus, tidak diperlukan kode tambahan untuk membuat instance dapat dipilih. Secara default, pickle akan mengambil kelas dan atribut dari sebuah instance melalui introspeksi. Ketika instance kelas tidak dipilih, metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 33 biasanya tidak dipanggil. Perilaku default pertama-tama membuat instance yang tidak diinisialisasi dan kemudian memulihkan atribut yang disimpan. Kode berikut menunjukkan penerapan perilaku ini
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj
Kelas dapat mengubah perilaku default dengan menyediakan satu atau beberapa metode khusus
objek. __getnewargs_ex__()Dalam protokol 2 dan yang lebih baru, kelas yang mengimplementasikan metode dapat mendikte nilai yang diteruskan ke metode setelah unpickling. Metode harus mengembalikan pasangan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 36 di mana args adalah tupel argumen posisional dan kwargs kamus argumen bernama untuk membangun objek. Itu akan diteruskan ke metode setelah dicabut
Anda harus menerapkan metode ini jika metode kelas Anda memerlukan argumen kata kunci saja. Jika tidak, disarankan agar kompatibilitas diterapkan
Berubah di versi 3. 6. sekarang digunakan dalam protokol 2 dan 3.
objek. __getnewargs__()Metode ini memiliki tujuan yang sama seperti , tetapi hanya mendukung argumen posisional. Itu harus mengembalikan Tuple argumen def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 42 yang akan diteruskan ke metode setelah unpickling
tidak akan dipanggil jika didefinisikan
Berubah di versi 3. 6. Sebelum Python 3. 6, dipanggil bukan di protokol 2 dan 3.
objek. __getstate__()Kelas selanjutnya dapat memengaruhi bagaimana instance mereka diasamkan dengan mengganti metode. Itu dipanggil dan objek yang dikembalikan diasamkan sebagai konten untuk instance, alih-alih status default. Ada beberapa kasus
Untuk kelas yang tidak memiliki instance dan no , status defaultnya adalah import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 0
Untuk kelas yang memiliki instance dan no , status defaultnya adalah def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 54
Untuk kelas yang memiliki instance dan , status defaultnya adalah tuple yang terdiri dari dua kamus. def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _54, dan nama slot pemetaan kamus ke nilai slot. Hanya slot yang memiliki nilai yang termasuk dalam yang terakhir
Untuk kelas yang memiliki dan tidak memiliki instance, status defaultnya adalah tuple yang item pertamanya adalah import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 0 dan item keduanya adalah nama slot pemetaan kamus ke nilai slot yang dijelaskan di poin sebelumnya
Berubah di versi 3. 11. Menambahkan implementasi default dari metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 27 di kelas.
objek. __setstatus__(status)Saat unpickling, jika class mendefinisikan , itu disebut dengan unpickled state. Dalam hal ini, tidak ada persyaratan untuk objek status menjadi kamus. Jika tidak, status acar harus berupa kamus dan itemnya ditetapkan ke kamus instance baru
Catatan
Jika mengembalikan nilai yang salah, metode tidak akan dipanggil saat unpickling
Lihat bagian untuk informasi selengkapnya tentang cara menggunakan metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 27 dan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 32
Catatan
Pada waktu unpickling, beberapa metode seperti def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 68, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 69, atau def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 70 dapat dipanggil pada instance. Jika metode tersebut bergantung pada beberapa invarian internal yang benar, tipe tersebut harus mengimplementasikan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 35 untuk membuat invarian seperti itu, karena def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 33 tidak dipanggil saat membongkar instance
Seperti yang akan kita lihat, acar tidak langsung menggunakan metode yang dijelaskan di atas. Faktanya, metode ini adalah bagian dari protokol penyalinan yang mengimplementasikan metode khusus import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 5. Protokol salin menyediakan antarmuka terpadu untuk mengambil data yang diperlukan untuk pengawetan dan penyalinan objek.
Meskipun kuat, menerapkan import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 _5 langsung di kelas Anda rawan kesalahan. Untuk alasan ini, desainer kelas harus menggunakan antarmuka tingkat tinggi (mis. e. , def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _34, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 27 dan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 32) jika memungkinkan. Kami akan menunjukkan, bagaimanapun, kasus di mana menggunakan import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 5 adalah satu-satunya pilihan atau mengarah ke pengawetan yang lebih efisien atau keduanya
objek. __reduce__()Antarmuka saat ini didefinisikan sebagai berikut. Metode ini tidak memerlukan argumen dan akan mengembalikan string atau sebaiknya tupel (objek yang dikembalikan sering disebut sebagai "nilai kurangi")
Jika sebuah string dikembalikan, string tersebut harus ditafsirkan sebagai nama variabel global. Itu harus menjadi nama lokal objek relatif terhadap modulnya; . Perilaku ini biasanya berguna untuk lajang
Ketika sebuah tuple dikembalikan, panjangnya harus antara dua dan enam item. Item opsional dapat dihilangkan, atau import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 0 dapat diberikan sebagai nilainya. Semantik dari setiap item sudah beres
Objek callable yang akan dipanggil untuk membuat versi awal objek
Tuple argumen untuk objek yang bisa dipanggil. Tuple kosong harus diberikan jika callable tidak menerima argumen apa pun
Secara opsional, status objek, yang akan diteruskan ke metode objek seperti yang dijelaskan sebelumnya. Jika objek tidak memiliki metode seperti itu, nilainya harus berupa kamus dan akan ditambahkan ke atribut objek
Opsional, iterator (dan bukan urutan) menghasilkan item yang berurutan. Barang-barang ini akan ditambahkan ke objek menggunakan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 83 atau, secara berkelompok, menggunakan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 84. Ini terutama digunakan untuk daftar subkelas, tetapi dapat digunakan oleh kelas lain selama mereka memiliki metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 85 dan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 86 dengan tanda tangan yang sesuai. (Apakah def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 85 atau def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 86 digunakan tergantung pada versi protokol acar mana yang digunakan serta jumlah item yang ditambahkan, jadi keduanya harus didukung. )
Secara opsional, iterator (bukan urutan) menghasilkan pasangan nilai kunci yang berurutan. Barang-barang ini akan disimpan ke objek menggunakan ________0______89. Ini terutama digunakan untuk subclass kamus, tetapi dapat digunakan oleh kelas lain selama mereka menerapkannya
Secara opsional, callable dengan tanda tangan ________0______91. Callable ini memungkinkan pengguna untuk secara terprogram mengontrol perilaku pembaruan status dari objek tertentu, alih-alih menggunakan metode statis class ZeroCopyByteArray(bytearray): def __reduce_ex__(self, protocol): if protocol >= 5: return type(self)._reconstruct, (PickleBuffer(self),), None else: # PickleBuffer is forbidden with pickle protocols <= 4. return type(self)._reconstruct, (bytearray(self),) @classmethod def _reconstruct(cls, obj): with memoryview(obj) as m: # Get a handle over the original buffer object obj = m.obj if type(obj) is cls: # Original buffer object is a ZeroCopyByteArray, return it # as-is. return obj else: return cls(obj) 6. Jika bukan import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 _0, panggilan ini akan diprioritaskan daripada class ZeroCopyByteArray(bytearray): def __reduce_ex__(self, protocol): if protocol >= 5: return type(self)._reconstruct, (PickleBuffer(self),), None else: # PickleBuffer is forbidden with pickle protocols <= 4. return type(self)._reconstruct, (bytearray(self),) @classmethod def _reconstruct(cls, obj): with memoryview(obj) as m: # Get a handle over the original buffer object obj = m.obj if type(obj) is cls: # Original buffer object is a ZeroCopyByteArray, return it # as-is. return obj else: return cls(obj) 6
Baru di versi 3. 8. Item tupel keenam opsional, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 91, telah ditambahkan.
Atau, metode dapat didefinisikan. Satu-satunya perbedaan adalah metode ini harus menggunakan argumen bilangan bulat tunggal, versi protokol. Saat ditentukan, acar akan lebih memilihnya daripada metode. Selain itu, secara otomatis menjadi sinonim untuk versi yang diperluas. Penggunaan utama untuk metode ini adalah untuk memberikan nilai pengurangan yang kompatibel dengan mundur untuk rilis Python yang lebih lama
Kegigihan Objek Eksternal
Untuk kepentingan kegigihan objek, modul mendukung gagasan referensi ke objek di luar aliran data acar. Objek tersebut direferensikan oleh ID persisten, yang harus berupa string karakter alfanumerik (untuk protokol 0) atau hanya objek arbitrer (untuk protokol yang lebih baru)
Resolusi ID persisten tersebut tidak ditentukan oleh modul;
Untuk memilih objek yang memiliki ID persisten eksternal, pickler harus memiliki metode khusus yang menggunakan objek sebagai argumen dan mengembalikan import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 0 atau ID persisten untuk objek tersebut. Ketika import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 _0 dikembalikan, pickler hanya mengasinkan objek seperti biasa. Saat string ID persisten dikembalikan, pickler akan mengambil objek tersebut, bersama dengan penanda sehingga unpickler akan mengenalinya sebagai ID persisten
Untuk menghapus objek eksternal, unpickler harus memiliki metode khusus yang menggunakan objek ID persisten dan mengembalikan objek yang direferensikan
Berikut adalah contoh komprehensif yang menyajikan bagaimana ID persisten dapat digunakan untuk mengambil objek eksternal dengan referensi
# Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _
Tabel Pengiriman
Jika seseorang ingin menyesuaikan pengawetan beberapa kelas tanpa mengganggu kode lain yang bergantung pada pengawetan, maka seseorang dapat membuat pengawetan dengan tabel pengiriman pribadi
Tabel pengiriman global yang dikelola oleh modul tersedia sebagai # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() 10. Oleh karena itu, seseorang dapat memilih untuk menggunakan salinan # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() 10 yang dimodifikasi sebagai tabel pengiriman pribadi
Misalnya
f = io.BytesIO() p = pickle.Pickler(f) p.dispatch_table = copyreg.dispatch_table.copy() p.dispatch_table[SomeClass] = reduce_SomeClass
membuat instance dari dengan tabel pengiriman pribadi yang menangani kelas # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() 13 secara khusus. Atau, kode
class MyPickler(pickle.Pickler): dispatch_table = copyreg.dispatch_table.copy() dispatch_table[SomeClass] = reduce_SomeClass f = io.BytesIO() p = MyPickler(f)
melakukan hal yang sama tetapi semua contoh # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _14 secara default akan berbagi tabel pengiriman pribadi. Di sisi lain, kode
copyreg.pickle(SomeClass, reduce_SomeClass) f = io.BytesIO() p = pickle.Pickler(f) _
memodifikasi tabel pengiriman global yang dibagikan oleh semua pengguna modul
Menangani Objek Stateful
Berikut adalah contoh yang menunjukkan cara memodifikasi perilaku pengawetan untuk suatu kelas. Kelas # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() 16 membuka file teks, dan mengembalikan nomor baris dan konten baris setiap kali metode # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() 17 dipanggil. Jika instance # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _16 diasamkan, semua atribut kecuali anggota objek file disimpan. Saat instance dilepas, file dibuka kembali, dan pembacaan dilanjutkan dari lokasi terakhir. Metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 32 dan def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 27 digunakan untuk menerapkan perilaku ini
class TextReader: """Print and number lines in a text file.""" def __init__(self, filename): self.filename = filename self.file = open(filename) self.lineno = 0 def readline(self): self.lineno += 1 line = self.file.readline() if not line: return None if line.endswith('\n'): line = line[:-1] return "%i: %s" % (self.lineno, line) def __getstate__(self): # Copy the object's state from self.__dict__ which contains # all our instance attributes. Always use the dict.copy() # method to avoid modifying the original state. state = self.__dict__.copy() # Remove the unpicklable entries. del state['file'] return state def __setstate__(self, state): # Restore instance attributes (i.e., filename and lineno). self.__dict__.update(state) # Restore the previously opened file's state. To do so, we need to # reopen it and read from it until the line count is restored. file = open(self.filename) for _ in range(self.lineno): file.readline() # Finally, save the file. self.file = file
Contoh penggunaan mungkin seperti ini
>>> reader = TextReader("hello.txt") >>> reader.readline() '1: Hello world!' >>> reader.readline() '2: I am line number two.' >>> new_reader = pickle.loads(pickle.dumps(reader)) >>> new_reader.readline() '3: Goodbye!'
Pengurangan Kustom untuk Jenis, Fungsi, dan Objek Lainnya
Baru di versi 3. 8
Terkadang, mungkin tidak cukup fleksibel. Secara khusus kita mungkin ingin menyesuaikan pengawetan berdasarkan kriteria lain selain jenis objek, atau kita mungkin ingin menyesuaikan pengawetan fungsi dan kelas
Untuk kasus tersebut, dimungkinkan untuk membuat subkelas dari kelas tersebut dan mengimplementasikan sebuah metode. Metode ini dapat mengembalikan tuple pengurangan sewenang-wenang (lihat import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 5). Alternatifnya dapat mengembalikan class ZeroCopyByteArray(bytearray): def __reduce_ex__(self, protocol): if protocol >= 5: return type(self)._reconstruct, (PickleBuffer(self),), None else: # PickleBuffer is forbidden with pickle protocols <= 4. return type(self)._reconstruct, (bytearray(self),) @classmethod def _reconstruct(cls, obj): with memoryview(obj) as m: # Get a handle over the original buffer object obj = m.obj if type(obj) is cls: # Original buffer object is a ZeroCopyByteArray, return it # as-is. return obj else: return cls(obj) _4 ke fallback ke perilaku tradisional
Jika kedua dan didefinisikan, maka metode diprioritaskan
Catatan
Untuk alasan performa, mungkin tidak dipanggil untuk objek berikut. import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 0, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 23, def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 24, dan contoh persis dari , , , , , , , , dan
Berikut adalah contoh sederhana di mana kami mengizinkan pengawetan dan merekonstruksi kelas tertentu
import io import pickle class MyClass: my_attribute = 1 class MyPickler(pickle.Pickler): def reducer_override(self, obj): """Custom reducer for MyClass.""" if getattr(obj, "__name__", None) == "MyClass": return type, (obj.__name__, obj.__bases__, {'my_attribute': obj.my_attribute}) else: # For any other object, fallback to usual reduction return NotImplemented f = io.BytesIO() p = MyPickler(f) p.dump(MyClass) del MyClass unpickled_class = pickle.loads(f.getvalue()) assert isinstance(unpickled_class, type) assert unpickled_class.__name__ == "MyClass" assert unpickled_class.my_attribute == 1 _
Buffer Out-of-band
Baru di versi 3. 8
Dalam beberapa konteks, modul digunakan untuk mentransfer data dalam jumlah besar. Oleh karena itu, penting untuk meminimalkan jumlah salinan memori, untuk mempertahankan kinerja dan konsumsi sumber daya. Namun, operasi normal modul, karena mengubah struktur objek seperti grafik menjadi aliran byte berurutan, secara intrinsik melibatkan penyalinan data ke dan dari aliran acar.
Batasan ini dapat dihindari jika penyedia (implementasi tipe objek yang akan ditransfer) dan konsumen (implementasi sistem komunikasi) mendukung fasilitas transfer out-of-band yang disediakan oleh protokol pickle 5 dan lebih tinggi
API penyedia
Objek data besar yang akan diambil harus menerapkan metode def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 98 khusus untuk protokol 5 dan lebih tinggi, yang mengembalikan sebuah instance (bukannya e. g. objek) untuk data besar apa pun
Objek memberi sinyal bahwa buffer yang mendasarinya memenuhi syarat untuk transfer data out-of-band. Objek tersebut tetap kompatibel dengan penggunaan modul secara normal. Namun, konsumen juga dapat ikut serta untuk mengatakan bahwa mereka akan menangani buffer tersebut sendiri
API Konsumen
Sebuah sistem komunikasi dapat mengaktifkan penanganan khusus dari objek yang dihasilkan saat membuat serial grafik objek
Di sisi pengirim, ia perlu meneruskan argumen buffer_callback ke (atau ke fungsi or ), yang akan dipanggil dengan masing-masing dihasilkan saat mengawetkan grafik objek. Buffer yang diakumulasikan oleh buffer_callback tidak akan melihat datanya disalin ke aliran acar, hanya penanda murah yang akan dimasukkan
Di sisi penerima, perlu meneruskan argumen buffer ke (atau ke fungsi or ), yang merupakan iterable dari buffer yang diteruskan ke buffer_callback. Iterable itu harus menghasilkan buffer dalam urutan yang sama seperti yang diteruskan ke buffer_callback. Buffer tersebut akan memberikan data yang diharapkan oleh rekonstruktor objek yang pengawetannya menghasilkan objek asli
Antara sisi pengirim dan sisi penerima, sistem komunikasi bebas menerapkan mekanisme transfernya sendiri untuk buffer out-of-band. Pengoptimalan potensial mencakup penggunaan memori bersama atau kompresi yang bergantung pada tipe data
Contoh
Berikut adalah contoh sepele di mana kami mengimplementasikan subkelas yang dapat berpartisipasi dalam pengawetan buffer out-of-band
class ZeroCopyByteArray(bytearray): def __reduce_ex__(self, protocol): if protocol >= 5: return type(self)._reconstruct, (PickleBuffer(self),), None else: # PickleBuffer is forbidden with pickle protocols <= 4. return type(self)._reconstruct, (bytearray(self),) @classmethod def _reconstruct(cls, obj): with memoryview(obj) as m: # Get a handle over the original buffer object obj = m.obj if type(obj) is cls: # Original buffer object is a ZeroCopyByteArray, return it # as-is. return obj else: return cls(obj)
Rekonstruktor (metode kelas # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _60) mengembalikan objek penyedia buffer jika memiliki tipe yang tepat. Ini adalah cara mudah untuk mensimulasikan perilaku zero-copy pada contoh mainan ini
Di sisi konsumen, kita dapat mengasinkan objek tersebut dengan cara biasa, yang jika tidak diserialisasi akan memberi kita salinan objek asli
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 0
Tetapi jika kita melewatkan buffer_callback dan kemudian mengembalikan buffer yang terakumulasi saat unserializing, kita bisa mendapatkan kembali objek aslinya
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _1
Contoh ini dibatasi oleh fakta yang mengalokasikan memorinya sendiri. Anda tidak dapat membuat instance yang didukung oleh memori objek lain. Namun, tipe data pihak ketiga seperti larik NumPy tidak memiliki batasan ini, dan memungkinkan penggunaan pengawetan tanpa salinan (atau membuat salinan sesedikit mungkin) saat mentransfer antar proses atau sistem yang berbeda
Lihat juga
PEP 574 – Protokol acar 5 dengan data out-of-band
Membatasi Global
Secara default, unpickling akan mengimpor kelas atau fungsi apa pun yang ditemukannya di data pickle. Untuk banyak aplikasi, perilaku ini tidak dapat diterima karena mengizinkan unpickler untuk mengimpor dan menjalankan kode arbitrer. Pertimbangkan saja apa yang dilakukan aliran data acar buatan tangan ini saat dimuat
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _2
Dalam contoh ini, unpickler mengimpor fungsi dan kemudian menerapkan argumen string "echo hello world". Meskipun contoh ini tidak menyinggung, tidak sulit membayangkan contoh yang dapat merusak sistem Anda
Untuk alasan ini, Anda mungkin ingin mengontrol apa yang akan dihilangkan dengan penyesuaian. Tidak seperti namanya, dipanggil setiap kali global (i. e. , kelas atau fungsi) diminta. Dengan demikian dimungkinkan untuk sepenuhnya melarang global atau membatasi mereka ke subset yang aman
Berikut adalah contoh unpickler yang memungkinkan hanya beberapa kelas aman dari modul yang akan dimuat
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _3
Contoh penggunaan unpickler kami berfungsi sebagaimana mestinya
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _4
Seperti yang ditunjukkan oleh contoh kami, Anda harus berhati-hati dengan apa yang Anda izinkan untuk tidak diawetkan. Oleh karena itu, jika keamanan menjadi perhatian, Anda mungkin ingin mempertimbangkan alternatif seperti menyusun API di atau solusi pihak ketiga
Pertunjukan
Versi terbaru dari protokol pickle (dari protokol 2 dan ke atas) menampilkan pengkodean biner yang efisien untuk beberapa fitur umum dan tipe bawaan. Juga, modul ini memiliki pengoptimal transparan yang ditulis dalam C
Contoh
Untuk kode yang paling sederhana, gunakan fungsi dan
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj 5
Contoh berikut membaca data acar yang dihasilkan
def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _6
Lihat juga
ModulRegistrasi konstruktor antarmuka acar untuk jenis ekstensi
ModulAlat untuk bekerja dengan dan menganalisis data acar
ModulDatabase objek yang diindeks;
ModulPenyalinan objek yang dangkal dan dalam
ModulSerialisasi kinerja tinggi dari tipe bawaan
Catatan kaki
Jangan bingung ini dengan modul
Inilah sebabnya mengapa fungsi tidak dapat diasamkan. semua def save(obj): return (obj.__class__, obj.__dict__) def restore(cls, attributes): obj = cls.__new__(cls) obj.__dict__.update(attributes) return obj _26 fungsi memiliki nama yang sama. # Simple example presenting how persistent ID can be used to pickle # external objects by reference. import pickle import sqlite3 from collections import namedtuple # Simple class representing a record in our database. MemoRecord = namedtuple("MemoRecord", "key, task") class DBPickler(pickle.Pickler): def persistent_id(self, obj): # Instead of pickling MemoRecord as a regular class instance, we emit a # persistent ID. if isinstance(obj, MemoRecord): # Here, our persistent ID is simply a tuple, containing a tag and a # key, which refers to a specific record in the database. return ("MemoRecord", obj.key) else: # If obj does not have a persistent ID, return None. This means obj # needs to be pickled as usual. return None class DBUnpickler(pickle.Unpickler): def __init__(self, file, connection): super().__init__(file) self.connection = connection def persistent_load(self, pid): # This method is invoked whenever a persistent ID is encountered. # Here, pid is the tuple returned by DBPickler. cursor = self.connection.cursor() type_tag, key_id = pid if type_tag == "MemoRecord": # Fetch the referenced record from the database and return it. cursor.execute("SELECT * FROM memos WHERE key=?", (str(key_id),)) key, task = cursor.fetchone() return MemoRecord(key, task) else: # Always raises an error if you cannot return the correct object. # Otherwise, the unpickler will think None is the object referenced # by the persistent ID. raise pickle.UnpicklingError("unsupported persistent object") def main(): import io import pprint # Initialize and populate our database. conn = sqlite3.connect(":memory:") cursor = conn.cursor() cursor.execute("CREATE TABLE memos(key INTEGER PRIMARY KEY, task TEXT)") tasks = ( 'give food to fish', 'prepare group meeting', 'fight with a zebra', ) for task in tasks: cursor.execute("INSERT INTO memos VALUES(NULL, ?)", (task,)) # Fetch the records to be pickled. cursor.execute("SELECT * FROM memos") memos = [MemoRecord(key, task) for key, task in cursor] # Save the records using our custom DBPickler. file = io.BytesIO() DBPickler(file).dump(memos) print("Pickled records:") pprint.pprint(memos) # Update a record, just for good measure. cursor.execute("UPDATE memos SET task='learn italian' WHERE key=1") # Load the records from the pickle data stream. file.seek(0) memos = DBUnpickler(file, conn).load() print("Unpickled records:") pprint.pprint(memos) if __name__ == '__main__': main() _80
Pengecualian yang diajukan kemungkinan besar akan menjadi atau tetapi bisa juga sesuatu yang lain
Modul menggunakan protokol ini untuk operasi penyalinan dangkal dan dalam
Keterbatasan karakter alfanumerik disebabkan oleh fakta bahwa ID persisten dalam protokol 0 dibatasi oleh karakter baris baru. Oleh karena itu, jika karakter baris baru apa pun muncul di ID persisten, data acar yang dihasilkan menjadi tidak dapat dibaca