Seite 1 von 1

json: float gerundet auf zwei Stellen hinterm Komma...

Verfasst: Montag 15. März 2010, 12:38
von jens
Ich möchte gern JSON erzeugen. Dabei sollen float Zahlen auf der zweiten Stelle hinter dem Komma gerundet werden.

So einfach scheint das aber nicht zu gehen. Ich sehe keine Möglichkeit das Format der bekannten Datentypen zu ändern. Man kann anscheinent die Ausgabe nur bei unbekannten Objekten beeinflussen.

Also nehme ich Decimal. Denn das kann JSON normalerweise nicht.

Code: Alles auswählen

import decimal
import json

class WeaveJSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, decimal.Decimal):
            #~ return "%.2f" % round(obj, 2) # -> "1.19"
            return round(obj, 2) # -> 1.1899999999999999

        return super(WeaveJSONEncoder, self).default(obj)


data = {"foo":decimal.Decimal('1.19'), "bar": 2.19}
print json.dumps(data, cls=WeaveJSONEncoder)
Wenn ich return round(obj, 2) mache, kommt das raus:

Code: Alles auswählen

{"foo": 1.1899999999999999, "bar": 2.1899999999999999
Ist auch klar. Decimal wird ja dann wieder zu einem float...

Mit return "%.2f" % round(obj, 2) erhalte ich aber Strings in JSON und keine Zahl mehr:

Code: Alles auswählen

{"foo": "1.19", "bar": "2.19"}
Das ist das Ziel:

Code: Alles auswählen

{"foo": 1.19, "bar": 2.19}

Verfasst: Montag 15. März 2010, 15:04
von jens
Hab nun was:

Code: Alles auswählen

import decimal
import json

class RoundedFloat(object):
    def __init__(self, value, places):
        self.value = value
        self.places = places

    def __str__(self):
        fmt = "%%.%sf" % self.places
        return fmt % round(self.value, self.places)

class WeaveJSONEncoder(json.JSONEncoder):
    def _iterencode_default(self, obj, markers=None):
        if isinstance(obj, RoundedFloat):
            return [str(obj)]
        else:
            return super(WeaveJSONEncoder, self)._iterencode_default(o, markers=markers)


data = {"foo":RoundedFloat(1.19, 2), "bar": RoundedFloat(1.19, 3)}
print json.dumps(data, cls=WeaveJSONEncoder)
Ausgabe:

Code: Alles auswählen

{"foo": 1.19, "bar": 1.190}
Aber schon recht umständlich...

EDIT: Sourcen aktualisiert.
Zeilen 10 + 11 sind unschön...

Verfasst: Montag 15. März 2010, 19:40
von BlackJack
@jens: Das sieht arg nach "Kosmetik" aus, denn wenn Du das wieder einliest bekommst Du ja wieder die "ungenauen" floats.

Re: json: float gerundet auf zwei Stellen hinterm Komma...

Verfasst: Montag 15. März 2010, 19:53
von Darii
jens hat geschrieben:Ich möchte gern JSON erzeugen. Dabei sollen float Zahlen auf der zweiten Stelle hinter dem Komma gerundet werden.

So einfach scheint das aber nicht zu gehen. Ich sehe keine Möglichkeit das Format der bekannten Datentypen zu ändern. Man kann anscheinent die Ausgabe nur bei unbekannten Objekten beeinflussen.
Du kannst die Funktion json.encode.floatstr durch eine eigene ersetzen(monkey patch).

Verfasst: Montag 15. März 2010, 19:58
von Hyperion
Vielleicht sind floats dann evtl. doch nicht die richtige Darstellungsform? Worum geht es denn konkret? Preise?

Verfasst: Montag 15. März 2010, 20:12
von lunar
@jens: Fließkommazahlen sollte man nur bei der Anzeige runden, nicht aber intern (sei es bei Berechnungen oder beim Datentransfer).

Verfasst: Dienstag 16. März 2010, 08:51
von jens
Ich weiß nicht genau, ob ich das auch wirklich brauche ;)

Es geht um http://code.google.com/p/django-weave/

Der Mozilla Weave Server sendet JSON mit Timestamps, die nur zwei Stellen hinter dem Komma haben. Ich kann noch nicht mir Sicherheit sagen, ob das Firefox Addon mit mehr Stellen klar kommt.

Mit ist noch was aufgefallen. Der Mozilla Server maskiert in JSON alle Slashes (z.B. in URLs) mit Backslashes. Der Python JSON Encoder macht das nicht. Ob es einen Unterschied macht, weiß ich auch noch nicht.

Verfasst: Dienstag 16. März 2010, 11:57
von BlackJack
@jens: Firefox wird das doch in JavaScript parsen!? Die Fliesskommazahlen sind doch da genau so "ungenau", d.h. wer auch immer das JSON parst bekommt aus 1.19 eine Fliesskommazahl die *so* nicht intern als IEE7irgendwas repräsentiert werden kann.

Und warum sollten die Backslashes Probleme machen? Das wird als JSON geparst und in JavaScript hat der Backslash in Zeichenketten doch auch so eine Bedeutung wie in Python.

Verfasst: Dienstag 16. März 2010, 14:30
von DasIch
Nutzt das json Modul einfach und wenn es ein Problem gibt mach ein Ticket auf. Willst du jetzt auch noch die JSON Spezifikation lesen um sicherzustellen dass da auch jeder eine Bibliothek nutzt die die richtig umsetzt?

Verfasst: Dienstag 16. März 2010, 15:09
von jens
Das Problem ist, das der sync noch nicht klappt. Um alle Fehlerquellen auszuschließen, habe ich meinen json response mit dem vom mozilla server verglichen und die Unterschiede gesehen.

Das runden der Zeiten, kommt ursprünglich aus anderen Python implementationen. Deswegen hab ich das übernommen.

So mache ich es z.Z.:

Code: Alles auswählen

def float_repr(f):
    return "%.2f" % round(f, 2)
json.encoder.FLOAT_REPR = float_repr
http://code.google.com/p/django-weave/s ... orators.py

Was bisher ein wenig Klappt ist das Syncronisieren der History und der Tabs. Bookmarks kommt zwar auch irgendwie an, aber nicht richtig eingeordnet.

Das Problem ist das Debuggen. Die API ist zwar dokumentiert: https://wiki.mozilla.org/Labs/Weave/API aber viele Fragen lässt es offen.

Verfasst: Dienstag 16. März 2010, 17:08
von Leonidas
jens hat geschrieben:So mache ich es z.Z.:

Code: Alles auswählen

def float_repr(f):
    return "%.2f" % round(f, 2)
json.encoder.FLOAT_REPR = float_repr
http://code.google.com/p/django-weave/s ... orators.py
Also das Monkeypatching ist ja gruselig für jeden der deinen Code als Lib einbinden will, der wundert sich dann ggf warum die Floats so fürchterlich falsch serialisiert werden.
jens hat geschrieben:Das Problem ist das Debuggen. Die API ist zwar dokumentiert: https://wiki.mozilla.org/Labs/Weave/API aber viele Fragen lässt es offen.
Und die Mozilla-Leute sind sicherlich nicht über IRC erreichbar um dort mal nachzufragen, statt herumzuraten?

Verfasst: Dienstag 16. März 2010, 17:23
von snafu
Leonidas hat geschrieben:Und die Mozilla-Leute sind sicherlich nicht über IRC erreichbar um dort mal nachzufragen, statt herumzuraten?
Ich glaub, die gehen früh ins Bett.

Verfasst: Dienstag 16. März 2010, 17:48
von jens
Der Monkeypatch ist nur eine Notlösung und sollte nicht ins "Endprodukt"...

Btw. das Abfragen mit dem Python Client funktioniert:
https://wiki.mozilla.org/Weave/Experime ... nts/Python