Saya mencoba untuk membuat representasi string JSON dari instance kelas dan mengalami kesulitan. Katakanlah kelas dibangun seperti ini:
class testclass:
value1 = "a"
value2 = "b"
Panggilan ke json.dumps dilakukan seperti ini:
t = testclass()
json.dumps(t)
Gagal dan memberi tahu saya bahwa testclass bukan JSON serializable.
TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable
Saya juga sudah mencoba menggunakan modul acar:
t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))
Dan itu memberikan informasi instance kelas tetapi bukan konten serial instance kelas.
b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'
Apa yang saya lakukan salah?
python
json
serialization
pickle
Feran
sumber
sumber
s = json.dumps(obj, default=lambda x: x.__dict__)
untuk variabel contoh cerita bersambung objek (self.value1
,self.value2
, ...). Ini cara paling sederhana dan paling lurus ke depan. Ini akan membuat cerita bersarang dari struktur objek bersarang. Thedefault
fungsi disebut ketika benda yang diberikan tidak langsung serializable. Anda juga dapat melihat jawaban saya di bawah ini. Saya menemukan jawaban populer tidak perlu rumit, yang mungkin benar sejak lama.testclass
tidak memiliki__init__()
metode, jadi semua instance akan berbagi dua atribut kelas yang sama (value1
danvalue2
) yang didefinisikan dalam pernyataan kelas. Apakah Anda memahami perbedaan antara kelas dan contoh dari satu kelas?Jawaban:
Masalah dasarnya adalah bahwa enkoder JSON
json.dumps()
hanya tahu cara membuat serial suatu rangkaian terbatas jenis objek secara default, semua tipe bawaan. Daftar di sini: https://docs.python.org/3.3/library/json.html#encoders-and-decodersSalah satu solusi yang baik adalah membuat kelas Anda mewarisi dari
JSONEncoder
dan kemudian mengimplementasikanJSONEncoder.default()
fungsi tersebut, dan membuat fungsi itu memancarkan JSON yang benar untuk kelas Anda.Sebuah solusi sederhana akan memanggil
json.dumps()
pada.__dict__
anggota contoh itu. Itu adalah standar Pythondict
dan jika kelas Anda sederhana itu akan menjadi JSON serializable.Pendekatan di atas dibahas dalam posting blog ini:
Menerialisasikan objek Python sewenang-wenang ke JSON menggunakan __dict__
sumber
.__init__()
fungsi metode, jadi instance kelas Anda memiliki kamus kosong. Dengan kata lain,{}
adalah hasil yang benar untuk kode contoh Anda.is not JSON serializable
Ada satu cara yang bagus untuk saya yang bisa Anda coba:
json.dumps()
dapat mengambil default parameter opsional tempat Anda dapat menentukan fungsi serializer khusus untuk jenis yang tidak dikenal, yang dalam kasus saya terlihat sepertiDua if pertama adalah untuk serialisasi tanggal dan waktu dan kemudian ada pengembalian
obj.__dict__
untuk objek lain.panggilan terakhir terlihat seperti:
Ini sangat baik ketika Anda membuat serial koleksi dan Anda tidak ingin menelepon
__dict__
secara eksplisit untuk setiap objek. Ini dilakukan untuk Anda secara otomatis.Sejauh ini bekerja sangat baik untuk saya, menantikan pikiran Anda.
sumber
NameError: name 'serialize' is not defined
. Ada tips?try: dict = obj.__dict__ except AttributeError: dict = {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)} return dict
Anda dapat menentukan
default
parameter bernama dalamjson.dumps()
fungsi:Penjelasan:
Bentuk dokumen ( 2.7 , 3.6 ):
(Bekerja pada Python 2.7 dan Python 3.x)
Catatan: Dalam hal ini Anda perlu
instance
variabel dan bukanclass
variabel, seperti contoh dalam pertanyaan yang coba dilakukan. (Saya mengasumsikan si penanya dimaksudkanclass instance
sebagai objek kelas)Saya belajar ini dulu dari jawaban @ phihag di sini . Menemukannya sebagai cara paling sederhana dan terbersih untuk melakukan pekerjaan itu.
sumber
default=lambda x: getattr(x, '__dict__', str(x))
datetime.date
adalah implementasi C karena itu tidak memiliki__dict__
atribut. IMHO demi keseragaman,datetime.date
harus memilikinya ...Saya hanya melakukan:
Ini bukan jawaban lengkap, dan jika Anda memiliki semacam kelas objek yang rumit, Anda tentu tidak akan mendapatkan semuanya. Namun saya menggunakan ini untuk beberapa objek sederhana saya.
Salah satu yang berfungsi dengan sangat baik adalah kelas "opsi" yang Anda dapatkan dari modul OptionParser. Ini dia bersama dengan permintaan JSON itu sendiri.
sumber
Menggunakan jsonpickle
sumber
JSON tidak benar-benar dimaksudkan untuk membuat serial objek Python sewenang-wenang. Ini bagus untuk serialisasi
dict
objek, tetapipickle
modul ini benar-benar apa yang seharusnya Anda gunakan secara umum. Keluaran daripickle
tidak benar-benar dapat dibaca manusia, tetapi seharusnya membongkar dengan baik. Jika Anda bersikeras menggunakan JSON, Anda bisa memeriksajsonpickle
modulnya, yang merupakan pendekatan hybrid yang menarik.https://github.com/jsonpickle/jsonpickle
sumber
Berikut adalah dua fungsi sederhana untuk serialisasi kelas non-canggih, tidak ada yang mewah seperti yang dijelaskan sebelumnya.
Saya menggunakan ini untuk hal-hal tipe konfigurasi karena saya dapat menambahkan anggota baru ke kelas tanpa penyesuaian kode.
sumber
Ada beberapa jawaban yang baik tentang bagaimana memulai melakukan ini. Tetapi ada beberapa hal yang perlu diingat:
__slots__
bukan__dict__
?json-trick adalah perpustakaan (yang saya buat dan kontribusi lainnya) yang telah dapat melakukan ini cukup lama. Sebagai contoh:
Anda akan mendapatkan instance Anda kembali. Di sini json terlihat seperti ini:
Jika Anda ingin membuat solusi sendiri, Anda mungkin melihat sumbernya
json-tricks
agar tidak melupakan beberapa kasus khusus (seperti__slots__
).Ia juga melakukan tipe lain seperti array numpy, datetimes, bilangan kompleks; itu juga memungkinkan untuk komentar.
sumber
Python3.x
Pendekatan terbaik yang bisa saya capai dengan pengetahuan saya adalah ini.
Perhatikan bahwa kode ini memperlakukan set () juga.
Pendekatan ini generik hanya membutuhkan ekstensi kelas (dalam contoh kedua).
Perhatikan bahwa saya hanya melakukannya ke file, tetapi mudah untuk mengubah perilaku sesuai selera Anda.
Namun ini adalah CoDec.
Dengan sedikit lebih banyak pekerjaan, Anda dapat membangun kelas Anda dengan cara lain. Saya menganggap konstruktor default untuk instance itu, lalu saya memperbarui dict kelas.
Edit
Dengan beberapa penelitian saya menemukan cara untuk menggeneralisasi tanpa perlu panggilan metode register SUPERCLASS , menggunakan metaclass
sumber
Saya percaya daripada pewarisan seperti yang disarankan dalam jawaban yang diterima, lebih baik menggunakan polimorfisme. Kalau tidak, Anda harus memiliki pernyataan if if big untuk menyesuaikan pengkodean setiap objek. Itu berarti membuat pembuat enkode default generik untuk JSON sebagai:
dan kemudian memiliki
jsonEnc()
fungsi di setiap kelas yang ingin Anda serialkan. misalnyaLalu kamu menelepon
json.dumps(classInstance,default=jsonDefEncoder)
sumber