Python JSON, Ondalık bir nesne serileştiriyor


242

Decimal('3.9')Bir nesnenin bir parçası olarak var ve bu gibi olması gereken bir JSON dizesine kodlamak istiyoruz {'x': 3.9}. Müşteri tarafında hassasiyet umurumda değil, bu yüzden bir şamandıra iyi.

Bunu serileştirmenin iyi bir yolu var mı? JSONDecoder Ondalık nesneleri kabul etmez ve önceden bir kayan noktaya dönüştürmek {'x': 3.8999999999999999}yanlıştır ve büyük bir bant genişliği kaybı olur.


2
ilgili Python hata: json kodlayıcı ondalık
işleyemiyor

3.8999999999999999 3.4'ten daha yanlış değildir. 0.2 tam şamandıra temsiline sahip değildir.
Jasen

@Jasen 3.89999999999 3.4 den% 12.8 daha yanlıştır. JSON standardı yalnızca serileştirme ve gösterimle ilgilidir, uygulama ile değil. IEEE754 kullanımı ham JSON spesifikasyonunun bir parçası değildir, onu uygulamanın en yaygın yolu budur. Yalnızca kesin ondalık aritmetik kullanan bir uygulama tamamen (aslında daha da kesin) uygundur.
hraban

😂 daha az yanlış. ironik.
hraban

Yanıtlar:


147

Alt sınıflamaya ne dersiniz json.JSONEncoder?

class DecimalEncoder(json.JSONEncoder):
    def _iterencode(self, o, markers=None):
        if isinstance(o, decimal.Decimal):
            # wanted a simple yield str(o) in the next line,
            # but that would mean a yield on the line with super(...),
            # which wouldn't work (see my comment below), so...
            return (str(o) for o in [o])
        return super(DecimalEncoder, self)._iterencode(o, markers)

Sonra şöyle kullanın:

json.dumps({'x': decimal.Decimal('5.5')}, cls=DecimalEncoder)

Ah, sadece bunun böyle çalışmadığını fark ettim. Buna göre düzenleyecektir. (Yine de fikir aynı kalır.)
Michał Marczyk

Sorun, DecimalEncoder()._iterencode(decimal.Decimal('3.9')).next()doğru olanı döndürdü '3.9', ancak DecimalEncoder()._iterencode(3.9).next()yalnızca '3.899...'bir başkasına yığıldığında dönecek bir jeneratör nesnesi döndürdü .next(). Jeneratör komik iş. Oh iyi ... Şimdi çalışmalı.
Michał Marczyk

8
Onun return (str(o),)yerine yapamaz mısın ? [o]1 elemanlı bir liste nedir, neden üzerinde döngü rahatsız?
mpen

2
@ Mark: return (str(o),)uzunluk 1 demetini döndürürken, yanıttaki
Abgan

30
Bu uygulama artık çalışmıyor. Elias Zamaria'nın biri aynı tarzda çalışan kişidir.
piro

223

Simplejson 2.1 ve üstü, Ondalık tip için yerel desteğe sahiptir:

>>> json.dumps(Decimal('3.9'), use_decimal=True)
'3.9'

Not use_decimalolduğu Truevarsayılan:

def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
    allow_nan=True, cls=None, indent=None, separators=None,
    encoding='utf-8', default=None, use_decimal=True,
    namedtuple_as_object=True, tuple_as_array=True,
    bigint_as_string=False, sort_keys=False, item_sort_key=None,
    for_json=False, ignore_nan=False, **kw):

Yani:

>>> json.dumps(Decimal('3.9'))
'3.9'

Umarım, bu özellik standart kütüphaneye dahil edilecektir.


7
Hmm, benim için bu Ondalık nesneleri yüzer hale getirir, bu kabul edilemez. Örneğin para ile çalışırken hassasiyet kaybı.
Matthew Schinckel

12
@MatthewSchinckel Bence değil. Aslında bir dize yapar. Ve sonuçtaki dizeyi json.loads(s, use_decimal=True)ona geri beslerseniz, ondalık işareti geri verir. Tüm süreçte yüzdürme yok. Yukarıdaki cevap düzenlendi. Umarım orijinal poster onunla iyidir.
Shekhar

1
Aha, bence use_decimal=Truede yükleri kullanmıyordum .
Matthew Schinckel

1
Benim için json.dumps({'a' : Decimal('3.9')}, use_decimal=True)verir '{"a": 3.9}'. Amaç değil miydi '{"a": "3.9"}'?
MrJ

5
simplejson.dumps(decimal.Decimal('2.2'))ayrıca çalışır: hiçbir açık use_decimal(simplejson / 3.6.0 üzerinde test edilmiştir). Geri yüklemek için başka bir yol: json.loads(s, parse_float=Decimal)yani, stdlib kullanarak okuyabilirsiniz json(ve eski simplejsonsürümleri de desteklenir).
jfs

181

Python 2.6.5 çalıştıran web sunucumda Michał Marczyk'in yanıtını denediğimi herkese bildirmek istiyorum ve iyi çalıştı. Ancak, Python 2.7'ye geçtim ve çalışmayı durdurdu. Ondalık nesneleri kodlamak için bir tür düşünmeye çalıştım ve bu ile geldi:

import decimal

class DecimalEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, decimal.Decimal):
            return float(o)
        return super(DecimalEncoder, self).default(o)

Bu, Python 2.7 ile sorun yaşayan herkese yardımcı olacaktır. Test ettim ve iyi çalışıyor gibi görünüyor. Birisi benim çözümümde herhangi bir hata fark ederse veya daha iyi bir yol bulursa, lütfen bana bildirin.


4
Python 2.7, şamandıraların yuvarlanması kurallarını değiştirdi, bu yüzden bu işe yarıyor. Stackoverflow.com/questions/1447287/…
Nelson

2
Simplejson (Google App Engine'de) kullanamayanlar için bu cevap bir nimettir.
Joel Cross

17
Hassasiyeti sağlamak için unicodeveya stryerine kullanın float.
Seppo Erviälä

2
54.3999 ... ile sorun Python 2.6.x ve daha eski sürümlerde önemliydi, burada dizeye dönüştürme kayan öğe düzenli olarak çalışmadı, ancak str'ye Ondalık dönüşüm çok daha yanlış çünkü çift tırnaklı dize olarak serileştirilecekti "54.4", bir sayı.
hynekcer

1
Python3'te çalışır
SeanFromIT

43

Python 2.7.11, Flask simya ('db.decimal' türleri ile) ve Flask Marshmallow ('anlık' serileştirici ve serileştirici için) kullanan Flask uygulamamda, her hata aldığımda bu hatayı aldım . Serileştirici ve serileştirici, Ondalık türleri herhangi bir JSON tanımlanabilir biçime dönüştüremedi.

Bir "pip install simplejson" yaptım, sonra sadece ekleyerek

import simplejson as json

serileştirici ve serileştirici yeniden akmaya başlar. Başka bir şey yapmadım ... DEciamls '234.00' şamandıra formatında gösterilir.


1
en kolay düzeltme
SMDC

1
İşin garibi, ithal etmek zorunda bile değilsiniz simplejson- sadece yüklemek hile yapar. Başlangıçta bu cevaptan bahsedildi .
bsplosion

Bu benim için çalışmıyor ve Decimal('0.00') is not JSON serializable pip ile yükledikten sonra hala var . Bu durum hem hatmi hem de grafen kullandığınız zamandır. Bir kalan API'de bir sorgu çağrıldığında, hatmi, ondalık alanlar için beklenen şekilde çalışır. Ancak graphql ile çağrıldığında bir is not JSON serializablehata yarattı .
Roel

Fantastik, Süper,
Örümcek Adam

Mükemmel! Bu, kolayca değiştiremeyeceğiniz bir başkası tarafından yazılmış bir modül kullandığınız durumlarda işe yarar (benim durumumda Google E-Tablolar'ı kullanmak için gspread)
happyskeptic

32

GAE 2.7 için simplejson'dan built json'a geçmeyi denedim ve ondalık sayıyla ilgili sorunlar yaşadım. Varsayılan str (o) döndürürse, tırnak işaretleri vardı (çünkü _iterencode varsayılan sonuçlarda _iterencode'u çağırır) ve float (o) izleyen 0'ı kaldıracaktır.

Varsayılan, float'tan (veya ek biçimlendirme olmadan repr'yi çağıran herhangi bir şeyden) ve özel __repr__ yöntemine sahip bir sınıfın nesnesini döndürürse, istediğim gibi çalışıyor gibi görünüyor.

import json
from decimal import Decimal

class fakefloat(float):
    def __init__(self, value):
        self._value = value
    def __repr__(self):
        return str(self._value)

def defaultencode(o):
    if isinstance(o, Decimal):
        # Subclass float with custom repr?
        return fakefloat(o)
    raise TypeError(repr(o) + " is not JSON serializable")

json.dumps([10.20, "10.20", Decimal('10.20')], default=defaultencode)
'[10.2, "10.20", 10.20]'

Güzel! Bu, ondalık değerin JSON'da Python'u en yakın float değerine yuvarlamadan bir Javascript float olarak bitmesini sağlar.
konrad

3
Ne yazık ki bu son Python 3'lerde çalışmıyor. Artık tüm float alt sınıflarını float olarak kabul eden ve bunlara tamamen repr demeyen bir hızlı yol kodu var.
Antti Haapala

@AnttiHaapala, örnek Python 3.6 üzerinde iyi çalışıyor.
Cristian Ciupitu

@CristianCiupitu, şimdi kötü davranışı yeniden üretemiyorum gibi görünüyor
Antti Haapala

2
Çözüm, v3.5.2rc1'den beri çalışmayı durdurdu, bkz. Github.com/python/cpython/commit/… . Orada float.__repr__(yani kesinlik kaybediyor) kodlandığı ve fakefloat.__repr__hiç çağrılmaz. Sahte çözümün ek yöntemi varsa, yukarıdaki çözüm 3.5.1'e kadar python3 için düzgün çalışır def __float__(self): return self.
myroslav

30

Yerel seçeneği eksik, bu yüzden onu arayan bir sonraki adam / safra için ekleyeceğim.

Django 1.7.x sürümünden itibaren DjangoJSONEncoderbunu alabileceğiniz bir yerleşik var django.core.serializers.json.

import json
from django.core.serializers.json import DjangoJSONEncoder
from django.forms.models import model_to_dict

model_instance = YourModel.object.first()
model_dict = model_to_dict(model_instance)

json.dumps(model_dict, cls=DjangoJSONEncoder)

Presto!


Bu bilmek harika olsa da, OP Django hakkında sormadı?
std''OrgnlDave

4
@ std''OrgnlDoğru 100% doğru. Buraya nasıl geldiğimi unuttum, ama arama terimine eklenmiş "django" ile bu soruyu googledim ve bu biraz daha googling yaptıktan sonra geldi, cevabı buldum ve benim gibi bir sonraki kişi için buraya ekledi, o
Javier Buzzi

6
benim günümü kurtarmak
gaozhidf

14

Benim $ 02!

Web sunucum için tonlarca veri serileştirdiğim için bir sürü JSON kodlayıcıyı genişletiyorum. İşte güzel bir kod. Hissettiğiniz herhangi bir veri formatına kolayca genişletilebilir ve 3.9"thing": 3.9

JSONEncoder_olddefault = json.JSONEncoder.default
def JSONEncoder_newdefault(self, o):
    if isinstance(o, UUID): return str(o)
    if isinstance(o, datetime): return str(o)
    if isinstance(o, time.struct_time): return datetime.fromtimestamp(time.mktime(o))
    if isinstance(o, decimal.Decimal): return str(o)
    return JSONEncoder_olddefault(self, o)
json.JSONEncoder.default = JSONEncoder_newdefault

Hayatımı çok kolaylaştırıyor ...


3
Bu yanlış: 3.9 olarak çoğaltacaktır "thing": "3.9".
Glif

hepsinin en iyi çözümleri, çok basit, günümü kurtardığınız için teşekkürler, benim için sayıyı kurtarmak için yeterlidir, ondalık için dize tamam
stackdave

@ JSON standartları üzerinden glif (birkaç tanesi vardır ...), alıntılanmamış bir sayı, ondalık sayı değil, çift kesinlikli kayar bir noktadır. Alıntı yapmak uyumluluğu garantilemenin tek yoludur.
std''OrgnlDave

2
bunun için bir alıntı var mı? Okuduğum her özellik onun uygulamaya bağlı olduğunu ima ediyor.
Glif

12

3.9IEEE şamandıralarında tam olarak temsil edilemez, her zaman olduğu gibi gelecektir 3.8999999999999999, örneğin deneyin print repr(3.9), buradan daha fazla bilgi edinebilirsiniz:

http://en.wikipedia.org/wiki/Floating_point
http://docs.sun.com/source/806-3568/ncg_goldberg.html

Bu nedenle, kayan nokta istemiyorsanız, yalnızca dize olarak göndermeniz ve ondalık nesnelerin JSON'a otomatik olarak dönüştürülmesine izin vermeniz için aşağıdaki gibi bir şey yapın:

import decimal
from django.utils import simplejson

def json_encode_decimal(obj):
    if isinstance(obj, decimal.Decimal):
        return str(obj)
    raise TypeError(repr(obj) + " is not JSON serializable")

d = decimal.Decimal('3.5')
print simplejson.dumps([d], default=json_encode_decimal)

İstemcide ayrıştırıldıktan sonra dahili olarak 3.9 olmayacağını biliyorum, ancak 3.9 geçerli bir JSON şamandıra. yani, json.loads("3.9")işe yarayacak ve ben bu olmak istiyorum
Knio

@Anurag Örneğinizde repr (o) yerine repr (obj) demek istediniz.
orokusaki

Ondalık olmayan bir şeyi kodlamaya çalışırsanız bu ölmeyecek mi?
mikemaccana

1
@ nailer, hayır denemez, bunu deneyebilirsiniz, bir sonraki işleyicinin kullanılması gerektiğini belirtmek için varsayılan yükselme istisnası olmak
Anurag Uniyal

1
Mikez302'nin cevabına bakın - Python 2.7 veya üstü sürümlerde bu geçerli değildir.
Joel Cross

9

Django kullanıcıları için :

Geçenlerde TypeError: Decimal('2337.00') is not JSON serializable JSON kodlama yanijson.dumps(data)

Çözüm :

# converts Decimal, Datetime, UUIDs to str for Encoding
from django.core.serializers.json import DjangoJSONEncoder  

json.dumps(response.data, cls=DjangoJSONEncoder)

Ama şimdi Ondalık değeri kullanarak, verileri deşifre zaman şimdi biz açıkça ondalık / şamandıra değeri ayrıştırıcı ayarlayabilirsiniz, bir dize olacaktır parse_floatseçeneği json.loads:

import decimal 

data = json.loads(data, parse_float=decimal.Decimal) # default is float(num_str)

8

Gönderen JSON Standart Belgesi , bağlantılı olarak json.org :

JSON sayıların anlambilimi konusunda agnostiktir. Herhangi bir programlama dilinde, sabit veya değişken, ikili veya ondalık sayılarda çeşitli kapasitelerde ve tamamlayıcılarda çeşitli tipler olabilir. Bu, farklı programlama dilleri arasındaki değişimi zorlaştırabilir. Bunun yerine JSON yalnızca insanların kullandığı sayıların temsilini sunar: bir basamak dizisi. Tüm programlama dilleri, dahili gösterimlere katılmıyor olsalar bile, basamak dizilerinin nasıl anlamlandırılacağını bilir. Bu değiş tokuşa izin vermek için yeterlidir.

Dolayısıyla, ondalık sayıları JSON'da sayı (dize yerine) olarak göstermek doğrudur. Körük soruna olası bir çözümdür.

Özel bir JSON kodlayıcı tanımlayın:

import json


class CustomJsonEncoder(json.JSONEncoder):

    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return super(CustomJsonEncoder, self).default(obj)

Ardından verilerinizi serileştirirken kullanın:

json.dumps(data, cls=CustomJsonEncoder)

Diğer cevaplardaki yorumlardan da belirtildiği gibi, python'un eski sürümleri float'a dönüştürülürken temsili bozabilir, ancak artık durum böyle değil.

Python'da ondalığı geri almak için:

Decimal(str(value))

Bu çözüm ondalık sayılarla ilgili Python 3.0 belgelerinde belirtilmiştir :

Bir kayan noktadan bir Ondalık oluşturmak için önce onu bir dizeye dönüştürün.


2
Bu dönüştürülüyor Python 3'te "sabit" değil float mutlaka size ondalık gösterimi kaybetmek ve yapar edecek tutarsızlıklara yol. Kullanılması Decimalönemliyse, dizeleri kullanmanın daha iyi olduğunu düşünüyorum.
juanpa.arrivillaga

Bunu python 3.1'den beri yapmanın güvenli olduğuna inanıyorum. Hassasiyet kaybı aritmetik işlemlerde zararlı olabilir, ancak JSON kodlaması durumunda, yalnızca değerin bir dize görüntüsünü üretersiniz, bu nedenle hassasiyet çoğu kullanım durumunda fazlasıyla yeterlidir. JSON'daki her şey zaten bir dizedir, bu yüzden değerin etrafına tırnak koymak sadece JSON spesifikasyonuna meydan okur.
Hugo Mota

Bununla birlikte, yüzmeye dönüşme konusundaki endişeleri anlıyorum. Muhtemelen istenen görüntü dizesini üretmek için kodlayıcı ile kullanılacak farklı bir strateji vardır. Yine de, teklif edilen bir değer üretmeye değer olduğunu sanmıyorum.
Hugo Mota

@HugoMota "JSON'daki her şey zaten bir dizedir, bu yüzden değerin etrafına tırnak koymak sadece JSON spesifikasyonuna meydan okur." No: rfc-editor.org/rfc/rfc8259.txt - JSON metin tabanlı bir kodlama biçimidir, ancak bu içindeki her şeyin bir dize olarak yorumlanması gerektiği anlamına gelmez. Spesifikasyon, sayıların dizelerden ayrı olarak nasıl kodlanacağını tanımlar.
Gunnar Magnór Magnússon

@ GunnarÞórMagnússon "JSON metin tabanlı bir kodlama biçimidir" - "her şey bir dizedir" ile kastediyorum. Sayıları önceden dizeye dönüştürmek hassas bir şekilde hassasiyeti korumaz, çünkü JSON olduğunda zaten bir dize olacaktır. Ve özelliklere göre, sayılar etrafında tırnak yok. Okurken hassasiyeti korumak okuyucunun sorumluluğundadır (bir alıntı değil, sadece benim almam).
Hugo Mota

6

Sınıfımdan çıkarılan şey bu

class CommonJSONEncoder(json.JSONEncoder):

    """
    Common JSON Encoder
    json.dumps(myString, cls=CommonJSONEncoder)
    """

    def default(self, obj):

        if isinstance(obj, decimal.Decimal):
            return {'type{decimal}': str(obj)}

class CommonJSONDecoder(json.JSONDecoder):

    """
    Common JSON Encoder
    json.loads(myString, cls=CommonJSONEncoder)
    """

    @classmethod
    def object_hook(cls, obj):
        for key in obj:
            if isinstance(key, six.string_types):
                if 'type{decimal}' == key:
                    try:
                        return decimal.Decimal(obj[key])
                    except:
                        pass

    def __init__(self, **kwargs):
        kwargs['object_hook'] = self.object_hook
        super(CommonJSONDecoder, self).__init__(**kwargs)

Birim testi geçen:

def test_encode_and_decode_decimal(self):
    obj = Decimal('1.11')
    result = json.dumps(obj, cls=CommonJSONEncoder)
    self.assertTrue('type{decimal}' in result)
    new_obj = json.loads(result, cls=CommonJSONDecoder)
    self.assertEqual(new_obj, obj)

    obj = {'test': Decimal('1.11')}
    result = json.dumps(obj, cls=CommonJSONEncoder)
    self.assertTrue('type{decimal}' in result)
    new_obj = json.loads(result, cls=CommonJSONDecoder)
    self.assertEqual(new_obj, obj)

    obj = {'test': {'abc': Decimal('1.11')}}
    result = json.dumps(obj, cls=CommonJSONEncoder)
    self.assertTrue('type{decimal}' in result)
    new_obj = json.loads(result, cls=CommonJSONDecoder)
    self.assertEqual(new_obj, obj)

json.loads(myString, cls=CommonJSONEncoder)yorum olmalıjson.loads(myString, cls=CommonJSONDecoder)
Can Kavaklıoğlu

obj ondalık değilse, object_hook için varsayılan bir dönüş değeri gerekir.
Can Kavaklıoğlu

3

Gereksiniminize göre özel bir JSON kodlayıcı oluşturabilirsiniz.

import json
from datetime import datetime, date
from time import time, struct_time, mktime
import decimal

class CustomJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return str(o)
        if isinstance(o, date):
            return str(o)
        if isinstance(o, decimal.Decimal):
            return float(o)
        if isinstance(o, struct_time):
            return datetime.fromtimestamp(mktime(o))
        # Any other serializer if needed
        return super(CustomJSONEncoder, self).default(o)

Dekoder bu şekilde çağrılabilir,

import json
from decimal import Decimal
json.dumps({'x': Decimal('3.9')}, cls=CustomJSONEncoder)

ve çıktı:

>>'{"x": 3.9}'

müthiş ... Bir durak çözüm için teşekkürler (y)
muhammed fesleğen

Bu gerçekten işe yarıyor!
Çözümünüzü

3

Üçüncü taraf bir kütüphane kullanmak istemeyenler için ... Elias Zamaria'nın cevabı ile ilgili bir sorun, şamandıraya dönüşmesi ve sorunlara yol açmasıdır. Örneğin:

>>> json.dumps({'x': Decimal('0.0000001')}, cls=DecimalEncoder)
'{"x": 1e-07}'
>>> json.dumps({'x': Decimal('100000000000.01734')}, cls=DecimalEncoder)
'{"x": 100000000000.01733}'

JSONEncoder.encode()Yöntem aksine sen, edebi json içeriği döndüren sağlar JSONEncoder.default()Eğer (şamandıra gibi) bir json uyumlu türü iade ettiği, daha sonra normal şekilde kodlanmış alır söyledi. Sorun, encode()(normalde) yalnızca en üst düzeyde çalışmasıdır. Ama biraz daha fazla çalışma ile hala kullanılabilir (python 3.x):

import json
from collections.abc import Mapping, Iterable
from decimal import Decimal

class DecimalEncoder(json.JSONEncoder):
    def encode(self, obj):
        if isinstance(obj, Mapping):
            return '{' + ', '.join(f'{self.encode(k)}: {self.encode(v)}' for (k, v) in obj.items()) + '}'
        if isinstance(obj, Iterable) and (not isinstance(obj, str)):
            return '[' + ', '.join(map(self.encode, obj)) + ']'
        if isinstance(obj, Decimal):
            return f'{obj.normalize():f}'  # using normalize() gets rid of trailing 0s, using ':f' prevents scientific notation
        return super().encode(obj)

Hangi size verir:

>>> json.dumps({'x': Decimal('0.0000001')}, cls=DecimalEncoder)
'{"x": 0.0000001}'
>>> json.dumps({'x': Decimal('100000000000.01734')}, cls=DecimalEncoder)
'{"x": 100000000000.01734}'

2

StdOrgnlDave cevabına dayanarak , kodlayıcı sadece projelerinizdeki belirli türler için çalışacak şekilde isteğe bağlı türlerle çağrılabilecek bu sarmalayıcıyı tanımladım. İşin kodunuzun içinde yapılması gerektiğine ve bu "varsayılan" kodlayıcıyı kullanmaması gerektiğine inanıyorum, çünkü "örtükten daha iyi açıktır", ancak bunu kullanarak zaman kazanacağınızı anlıyorum. :-)

import time
import json
import decimal
from uuid import UUID
from datetime import datetime

def JSONEncoder_newdefault(kind=['uuid', 'datetime', 'time', 'decimal']):
    '''
    JSON Encoder newdfeault is a wrapper capable of encoding several kinds
    Use it anywhere on your code to make the full system to work with this defaults:
        JSONEncoder_newdefault()  # for everything
        JSONEncoder_newdefault(['decimal'])  # only for Decimal
    '''
    JSONEncoder_olddefault = json.JSONEncoder.default

    def JSONEncoder_wrapped(self, o):
        '''
        json.JSONEncoder.default = JSONEncoder_newdefault
        '''
        if ('uuid' in kind) and isinstance(o, uuid.UUID):
            return str(o)
        if ('datetime' in kind) and isinstance(o, datetime):
            return str(o)
        if ('time' in kind) and isinstance(o, time.struct_time):
            return datetime.fromtimestamp(time.mktime(o))
        if ('decimal' in kind) and isinstance(o, decimal.Decimal):
            return str(o)
        return JSONEncoder_olddefault(self, o)
    json.JSONEncoder.default = JSONEncoder_wrapped

# Example
if __name__ == '__main__':
    JSONEncoder_newdefault()

0

Ondalık içeren bir sözlüğü requestskütüphaneye aktarmak istiyorsanız ( jsonanahtar kelime bağımsız değişkenini kullanarak ), yüklemeniz yeterlidir simplejson:

$ pip3 install simplejson    
$ python3
>>> import requests
>>> from decimal import Decimal
>>> # This won't error out:
>>> requests.post('https://www.google.com', json={'foo': Decimal('1.23')})

Sorunun nedeni olmasıdır requestskullandığı simplejsonMevcut olması halinde, geri yerleşik düşüyor jsoneğer yüklü değil.


-6

bu ekleyerek yapılabilir

    elif isinstance(o, decimal.Decimal):
        yield str(o)

içinde \Lib\json\encoder.py:JSONEncoder._iterencode, ama daha iyi bir çözüm için umuyordum


5
JSONEncoder'ı yukarıda örneklendiği gibi alt sınıflara ayırabilirsiniz, kurulu bir kütüphanenin kurulu Python dosyalarını düzenlemek veya yorumlayıcının kendisi son çare olmalıdır.
justanr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.