Saya menggunakan modul json standar di python 2.6 untuk membuat daftar pelampung. Namun, saya mendapatkan hasil seperti ini:
>>> import json
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
Saya ingin float diformat dengan hanya dua digit desimal. Outputnya akan terlihat seperti ini:
>>> json.dumps([23.67, 23.97, 23.87])
'[23.67, 23.97, 23.87]'
Saya telah mencoba menentukan kelas JSON Encoder saya sendiri:
class MyEncoder(json.JSONEncoder):
def encode(self, obj):
if isinstance(obj, float):
return format(obj, '.2f')
return json.JSONEncoder.encode(self, obj)
Ini berfungsi untuk satu objek float:
>>> json.dumps(23.67, cls=MyEncoder)
'23.67'
Tetapi gagal untuk objek bersarang:
>>> json.dumps([23.67, 23.97, 23.87])
'[23.670000000000002, 23.969999999999999, 23.870000000000001]'
Saya tidak ingin memiliki dependensi eksternal, jadi saya lebih suka menggunakan modul json standar.
Bagaimana saya bisa mencapai ini?
sumber
original_float_repr = encoder.FLOAT_REPR
encoder.FLOAT_REPR = lambda o: format(o, '.2f')
print json.dumps(1.0001)
encoder.FLOAT_REPR = original_float_repr
23.67
untuk melihat bagaimana.2f
tidak dihormati.memancarkan
Tidak perlu monkeypatching.
sumber
pretty_floats
fungsinya dan hanya mengintegrasikannya ke kode saya yang lain.list( map(pretty_floats, obj) )
map
mengembalikan iterator, bukanlist
Jika Anda menggunakan Python 2.7, solusi sederhana adalah dengan membulatkan float Anda secara eksplisit ke presisi yang diinginkan.
Ini berfungsi karena Python 2.7 membuat pembulatan float lebih konsisten . Sayangnya ini tidak berfungsi di Python 2.6:
Solusi yang disebutkan di atas adalah solusi untuk 2.6, tetapi tidak ada yang sepenuhnya memadai. Penambalan monyet json.encoder.FLOAT_REPR tidak berfungsi jika waktu proses Python Anda menggunakan versi C dari modul JSON. Kelas PrettyFloat dalam jawaban Tom Wuttke berfungsi, tetapi hanya jika pengkodean% g berfungsi secara global untuk aplikasi Anda. % .15g agak ajaib, ini berfungsi karena presisi float adalah 17 digit signifikan dan% g tidak mencetak nol di belakangnya.
Saya menghabiskan beberapa waktu mencoba membuat PrettyFloat yang memungkinkan penyesuaian presisi untuk setiap angka. Yaitu, sintaks seperti
Tidak mudah untuk melakukannya dengan benar. Mewarisi dari float itu canggung. Mewarisi dari Object dan menggunakan subclass JSONEncoder dengan metode default () -nya sendiri seharusnya berfungsi, kecuali modul json tampaknya menganggap semua jenis kustom harus diserialkan sebagai string. Yaitu: Anda berakhir dengan string Javascript "0,33" pada output, bukan angka 0,33. Mungkin masih ada cara untuk membuat ini berhasil, tetapi ini lebih sulit daripada kelihatannya.
sumber
Sungguh disayangkan bahwa
dumps
tidak memungkinkan Anda melakukan apa pun untuk mengapung. Namunloads
demikian. Jadi, jika Anda tidak keberatan dengan beban CPU tambahan, Anda dapat membuangnya melalui encoder / decoder / encoder dan mendapatkan hasil yang benar:sumber
parse_float
kwarg!Berikut adalah solusi yang berhasil untuk saya dengan Python 3 dan tidak memerlukan tambalan monyet:
Outputnya adalah:
Ini menyalin data tetapi dengan float bulat.
sumber
Jika Anda terjebak dengan Python 2.5 atau versi sebelumnya: Trik monkey-patch tidak bekerja dengan modul simplejson asli jika speedup C diinstal:
sumber
Anda dapat melakukan apa yang perlu Anda lakukan, tetapi itu tidak didokumentasikan:
sumber
FLOAT_REPR
konstanta dalamjson.encoder
modul.Solusi Alex Martelli akan berfungsi untuk aplikasi utas tunggal, tetapi mungkin tidak berfungsi untuk aplikasi multi utas yang perlu mengontrol jumlah tempat desimal per utas. Berikut adalah solusi yang seharusnya berfungsi di aplikasi multi-utas:
Anda cukup menyetel encoder.thread_local.decimal_places ke jumlah tempat desimal yang Anda inginkan, dan panggilan berikutnya ke json.dumps () di utas itu akan menggunakan jumlah tempat desimal itu
sumber
Jika Anda perlu melakukan ini di python 2.7 tanpa menimpa json.encoder.FLOAT_REPR global, inilah salah satu caranya.
Kemudian, di python 2.7:
Di python 2.6, itu tidak berfungsi seperti yang ditunjukkan oleh Matthew Schinckel di bawah ini:
sumber
Kelebihan:
Kekurangan:
Kompleksitas kuadrat.
sumber
Saat mengimpor modul json standar, cukup mengubah encoder default FLOAT_REPR. Sebenarnya tidak perlu mengimpor atau membuat instance Encoder.
Kadang-kadang juga sangat berguna untuk menampilkan json representasi terbaik yang dapat ditebak python dengan str. Ini akan memastikan angka-angka penting tidak diabaikan.
sumber
Saya setuju dengan @Nelson bahwa mewarisi dari float itu canggung, tetapi mungkin solusi yang hanya menyentuh
__repr__
fungsi mungkin bisa dimaafkan. Saya akhirnya menggunakandecimal
paket untuk ini untuk memformat ulang float saat diperlukan. Keuntungannya adalah bahwa ini berfungsi dalam semua konteks di manarepr()
dipanggil, begitu juga ketika hanya mencetak daftar ke stdout misalnya. Selain itu, ketepatan dapat dikonfigurasi waktu proses, setelah data dibuat. Kelemahannya tentu saja bahwa data Anda perlu diubah ke kelas float khusus ini (sayangnya Anda tidak dapat menggunakan patch monyetfloat.__repr__
). Untuk itu saya berikan fungsi konversi singkat.Kode:
Contoh penggunaan:
sumber
Menggunakan numpy
Jika Anda benar-benar memiliki pelampung yang sangat panjang, Anda dapat membulatkannya ke atas / bawah dengan benar dengan numpy:
'[23.67, 23.97, 23.87]'
sumber
Saya baru saja merilis fjson , pustaka Python kecil untuk memperbaiki masalah ini. Pasang dengan
dan gunakan seperti itu
json
, dengan penambahanfloat_format
parameter:sumber