OK, going back to your original question:
On Thu, 8 Aug 2019 at 11:24, Richard Musil
If I use Decimal, the value is preserved, but there seems to be no way to "serialize it back". Writing a custom serializer:
class DecimalEncoder(json.JSONEncoder): def default(self, o): if isinstance(o, decimal.Decimal): return str(o) # <- This becomes quoted in the serialized output return super.default(o)
seems to only allow returning "string" value, but then serializes it as a string! I.e. with the double quotes. What seems to be missing is an ability to return a "raw textual representation" of the serialized object which will not get mangled further by the `json` module.
The thing is, if you were allowed to insert arbitrary text (your "raw textual representation") into a JSON stream, the result wouldn't be JSON any more. If you want to dump user-defined types in a JSON stream, you need to do so by defining a structure (defined in terms of the fundamental types that JSON supports) that you can serialise to the JSON stream. That's why the encoder default() method returns an object, not a string. So, for example, you could serialise and deserialise decimals as follows:
import json import decimal
class DecimalEncoder(json.JSONEncoder): ... def default(self, o): ... if isinstance(o, decimal.Decimal): ... # Return a JSON "object" with 2 attributes: type="Decimal", value=the string representation of the value ... return {"type": "Decimal", "value": str(o)} ... return super.default(o) ...
def as_decimal(dct): ... if dct.get("type") == "Decimal" and "value" in dct: ... return decimal.Decimal(dct["value"]) ... x = json.dumps([12, 34.56, decimal.Decimal("789.876")], cls=DecimalEncoder) x '[12, 34.56, {"type": "Decimal", "value": "789.876"}]' json.loads(x, object_hook=as_decimal) [12, 34.56, Decimal('789.876')]
What you *can't* do is change how the fundamental types are represented, or have a specialised deserialiser for anything that's not a JSON "object" type. The point of the customisation facility is to transport non-JSON types via a JSON stream, retaining type information. Not to modify how the JSON stream is represented as a string. So no, I don't think there's any fundamental asymmetry here, nor do I think there's anything particular missing[1]. I just think you've misunderstood the purpose behind the customisation facilities in the json module. Paul [1] Assuming you accept that controlling the exact serialisation of fundamental JSON types is a non-goal, which you claim you do accept, even though your use case seems based on the idea that you want to be able to serialise floating point numbers in a consistent format across different JSON libraries...