Saya memiliki Decimal('3.9')
sebagai bagian dari objek, dan ingin menyandikan ini ke string JSON yang seharusnya terlihat {'x': 3.9}
. Saya tidak peduli tentang presisi di sisi klien, jadi float baik-baik saja.
Apakah ada cara yang baik untuk membuat cerita bersambung ini? JSONDecoder tidak menerima objek Desimal, dan mengkonversi ke float sebelumnya menghasilkan {'x': 3.8999999999999999}
yang salah, dan akan menjadi pemborosan bandwidth yang besar.
Jawaban:
Bagaimana dengan subklas
json.JSONEncoder
?Kemudian gunakan seperti ini:
sumber
DecimalEncoder()._iterencode(decimal.Decimal('3.9')).next()
mengembalikan yang benar'3.9'
, tetapiDecimalEncoder()._iterencode(3.9).next()
mengembalikan objek generator yang hanya akan kembali'3.899...'
ketika Anda menumpuk yang lain.next()
. Bisnis pembangkit lucu. Oh well ... Harusnya bekerja sekarang.return (str(o),)
sebaliknya?[o]
adalah daftar dengan hanya 1 elemen, mengapa repot-repot mengulanginya?return (str(o),)
akan mengembalikan tuple dengan panjang 1, sedangkan kode dalam jawaban mengembalikan generator dengan panjang 1. Lihat iterencode () docsSimplejson 2.1 dan lebih tinggi memiliki dukungan asli untuk tipe Desimal:
Perhatikan bahwa
use_decimal
secaraTrue
default:Begitu:
Semoga fitur ini akan dimasukkan dalam perpustakaan standar.
sumber
json.loads(s, use_decimal=True)
itu memberi Anda kembali desimal. Tidak mengapung di seluruh proses. Diedit jawaban di atas. Berharap poster asli tidak masalah dengan itu.use_decimal=True
beban juga.json.dumps({'a' : Decimal('3.9')}, use_decimal=True)
memberi'{"a": 3.9}'
. Apakah tujuannya bukan'{"a": "3.9"}'
?simplejson.dumps(decimal.Decimal('2.2'))
juga berfungsi: tidak ada yang eksplisituse_decimal
(diuji pada simplejson / 3.6.0). Cara lain untuk memuatnya kembali adalah:json.loads(s, parse_float=Decimal)
yaitu, Anda dapat membacanya menggunakan stdlibjson
(dansimplejson
versi lama juga didukung).Saya ingin memberi tahu semua orang bahwa saya mencoba jawaban Michał Marczyk di server web saya yang menjalankan Python 2.6.5 dan berfungsi dengan baik. Namun, saya memutakhirkan ke Python 2.7 dan berhenti bekerja. Saya mencoba memikirkan semacam cara untuk menyandikan objek Desimal dan inilah yang saya buat:
Semoga ini dapat membantu siapa saja yang memiliki masalah dengan Python 2.7. Saya mengujinya dan tampaknya berfungsi dengan baik. Jika ada yang melihat adanya bug dalam solusi saya atau mencari cara yang lebih baik, beri tahu saya.
sumber
unicode
ataustr
alih-alihfloat
untuk memastikan ketepatan."54.4"
, bukan sebagai sebuah angka.Dalam aplikasi Flask saya, Yang menggunakan python 2.7.11, alkimia flask (dengan tipe 'db.decimal'), dan Flask Marshmallow (untuk serializer dan deserializer 'instan'), saya mengalami kesalahan ini, setiap kali saya melakukan GET atau POST . Serializer dan deserializer, gagal mengubah tipe Desimal menjadi format JSON yang dapat diidentifikasi.
Saya melakukan "pip install simplejson", lalu Hanya dengan menambahkan
serializer dan deserializer mulai mendengkur lagi. Saya tidak melakukan apa-apa lagi ... DEciamls ditampilkan sebagai format float '234.00'.
sumber
simplejson
- hanya menginstalnya saja. Awalnya disebutkan oleh jawaban ini .Decimal('0.00') is not JSON serializable
setelah menginstalnya melalui pip. Situasi ini adalah ketika Anda menggunakan marshmallow dan graphene. Ketika kueri dipanggil pada api sisa, marshmallow bekerja dengan harapan untuk bidang desimal. Namun ketika dipanggil dengan graphql itu menimbulkanis not JSON serializable
kesalahan.Saya mencoba beralih dari simplejson ke builtin json untuk GAE 2.7, dan memiliki masalah dengan desimal. Jika default mengembalikan str (o) ada tanda kutip (karena _iterencode memanggil _iterencode pada hasil default), dan float (o) akan menghapus trailing 0.
Jika default mengembalikan objek kelas yang diwarisi dari float (atau apa pun yang memanggil repr tanpa pemformatan tambahan) dan memiliki metode __repr__ khusus, sepertinya berfungsi seperti yang saya inginkan.
sumber
float.__repr__
hardcoded (yang kehilangan presisi), danfakefloat.__repr__
tidak disebut sama sekali. Solusi di atas tidak berfungsi dengan baik untuk python3 hingga 3.5.1, jika fakefloat memiliki metode tambahandef __float__(self): return self
.Opsi asli tidak ada sehingga saya akan menambahkannya untuk cowok / empedu berikutnya yang mencarinya.
Mulai dari Django 1.7.x ada built-in
DjangoJSONEncoder
yang bisa Anda dapatkandjango.core.serializers.json
.Presto!
sumber
$ 0,02 saya!
Saya memperpanjang sekelompok enkoder JSON karena saya membuat serialisasi banyak data untuk server web saya. Ini beberapa kode yang bagus. Perhatikan bahwa mudah diperluas ke hampir semua format data yang Anda suka dan akan mereproduksi 3,9 sebagai
"thing": 3.9
Membuat hidup saya jauh lebih mudah ...
sumber
"thing": "3.9"
.3.9
tidak dapat direpresentasikan secara tepat di IEEE float, itu akan selalu datang seperti3.8999999999999999
, misalnya cobaprint repr(3.9)
, Anda dapat membaca lebih lanjut di sini:http://en.wikipedia.org/wiki/Floating_point
http://docs.sun.com/source/806-3568/ncg_goldberg.html
Jadi jika Anda tidak ingin float, hanya opsi yang harus Anda kirimkan sebagai string, dan untuk memungkinkan konversi objek desimal otomatis ke JSON, lakukan sesuatu seperti ini:
sumber
json.loads("3.9")
akan bekerja, dan saya ingin iniUntuk pengguna Django :
Baru-baru ini menemukan
TypeError: Decimal('2337.00') is not JSON serializable
sementara yaitu JSON encodingjson.dumps(data)
Solusi :
Tapi, sekarang nilai Desimal akan menjadi string, sekarang kita dapat secara eksplisit mengatur parser nilai desimal / float saat mendekode data, menggunakan
parse_float
opsi dijson.loads
:sumber
Dari Dokumen Standar JSON , sebagaimana ditautkan di json.org :
Jadi sebenarnya akurat untuk menggambarkan Desimal sebagai angka (bukan string) di JSON. Di bawah ini terletak solusi yang mungkin untuk masalah tersebut.
Tentukan pembuat JSON khusus:
Kemudian gunakan saat membuat serialisasi data Anda:
Seperti dicatat dari komentar pada jawaban lain, versi python yang lebih lama mungkin mengacaukan representasi ketika mengonversi menjadi float, tetapi itu tidak terjadi lagi.
Untuk mendapatkan kembali desimal dengan Python:
Solusi ini diisyaratkan dalam dokumentasi Python 3.0 pada desimal :
sumber
float
tentu membuat Anda kehilangan representasi desimal, dan akan menyebabkan perbedaan. JikaDecimal
penting untuk digunakan, saya pikir lebih baik menggunakan string.Inilah yang saya miliki, diambil dari kelas kami
Yang lolos paling tidak:
sumber
json.loads(myString, cls=CommonJSONEncoder)
komentar harusjson.loads(myString, cls=CommonJSONDecoder)
Anda dapat membuat enkode JSON khusus sesuai kebutuhan Anda.
Decoder bisa disebut seperti ini,
dan hasilnya adalah:
sumber
Bagi mereka yang tidak ingin menggunakan perpustakaan pihak ketiga ... Masalah dengan jawaban Elias Zamaria adalah bahwa itu dikonversi menjadi mengambang, yang dapat mengalami masalah. Sebagai contoh:
The
JSONEncoder.encode()
Metode memungkinkan Anda mengembalikan konten json literal, sepertiJSONEncoder.default()
yang telah Anda kembali jenis kompatibel json (seperti float) yang kemudian akan dikodekan dengan cara biasa. Masalah denganencode()
itu (biasanya) hanya bekerja di tingkat atas. Tapi itu masih bisa digunakan, dengan sedikit kerja ekstra (python 3.x):Yang memberi Anda:
sumber
Berdasarkan jawaban stdOrgnlDave, saya telah mendefinisikan pembungkus ini yang dapat dipanggil dengan jenis opsional sehingga pembuat enkode hanya akan bekerja untuk jenis tertentu di dalam proyek Anda. Saya percaya pekerjaan harus dilakukan di dalam kode Anda dan tidak menggunakan encoder "default" ini karena "itu lebih baik eksplisit daripada implisit", tapi saya mengerti menggunakan ini akan menghemat waktu Anda. :-)
sumber
Jika Anda ingin meneruskan kamus berisi desimal ke
requests
perpustakaan (menggunakanjson
argumen kata kunci), Anda hanya perlu menginstalsimplejson
:Alasan masalahnya adalah yang hanya
requests
digunakansimplejson
jika ada, dan kembali ke bawaanjson
jika tidak diinstal.sumber
ini bisa dilakukan dengan menambahkan
masuk
\Lib\json\encoder.py:JSONEncoder._iterencode
, tapi saya berharap untuk solusi yang lebih baiksumber