简体   繁体   中英

Encoding floats in a dictionary using custom python JSON encoder

Here's a simple JSON encoder that convert float values to string:

class NestedEncoder(json.JSONEncoder):
    '''
    A JSON Encoder that converts floats/decimals to strings and allows nested objects
    '''

    def default(self, obj):

        if isinstance(obj, float) or obj.__class__.__name__ == "float32":
            return self.floattostr(obj)
        elif obj.__class__.__name__ == "type":
            return str(obj)
        elif hasattr(obj, 'repr_json'):
            return obj.repr_json()
        else:
            return json.JSONEncoder.default(self, obj)

    def floattostr(self,o,_inf=float('Inf'), _neginf=-float('-Inf'),nan_str="None"):
        if o != o:
            text = nan_str
        elif o == _inf:
            text = 'Infinity'
        elif o == _neginf:
            text = '-Infinity'
        else:
            return o.__repr__()

        return text

Now here's two tests. The first creates a Infinity valued float and encodes it using the custom encoder. Test passes.

def test_inf():
    inf = float('Inf')
    as_json = json.dumps(inf,cls=NestedEncoder)
    assert as_json == "Infinity"

The second test does the same but puts the float in a dictionary:

def test_inf_dic():
    inf = float('Inf')
    as_json = json.dumps({'key':inf},cls=NestedEncoder)
    assert as_json == "{'key':'Infinity'}"

OUTPUT:

=================================== FAILURES ===================================
_________________________________ test_inf_dic _________________________________

    def test_inf_dic():
        inf = float('Inf')
        as_json = json.dumps({'key':inf},cls=NestedEncoder)
>       assert as_json == "{'key':'Infinity'}"
E       assert '{"key": Infinity}' == "{'key':'Infinity'}"
E         - {"key": Infinity}
E         ?  ^   ^ ^
E         + {'key':'Infinity'}
E         ?  ^   ^ ^        +

EDIT:

The custom encoder only gets called for the first test, not the second.

You are correct that your custom function is not getting called during your test. The reason for this is explained in the docs:

If specified, default should be a function that gets called for objects that can't otherwise be serialized. It should return a JSON encodable version of the object or raise a TypeError. If not specified, TypeError is raised.

Since float is an object that it already knows how to serialized, it is not called. For float serialization, you can override the encode function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM