]> granicus.if.org Git - python/commitdiff
Issue #26719: More efficient formatting of ints and floats in json.
authorSerhiy Storchaka <storchaka@gmail.com>
Sun, 10 Apr 2016 11:41:19 +0000 (14:41 +0300)
committerSerhiy Storchaka <storchaka@gmail.com>
Sun, 10 Apr 2016 11:41:19 +0000 (14:41 +0300)
Lib/json/encoder.py
Modules/_json.c

index 26e9eb2bc69255a400a3c48686a1f821cab562db..d596489f42d3856db96f507e1f04d410d154b58e 100644 (file)
@@ -32,7 +32,6 @@ for i in range(0x20):
     #ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
 
 INFINITY = float('inf')
-FLOAT_REPR = repr
 
 def py_encode_basestring(s):
     """Return a JSON representation of a Python string
@@ -221,7 +220,7 @@ class JSONEncoder(object):
             _encoder = encode_basestring
 
         def floatstr(o, allow_nan=self.allow_nan,
-                _repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
+                _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
             # Check for specials.  Note that this type of test is processor
             # and/or platform-specific, so do tests which don't depend on the
             # internals.
@@ -268,6 +267,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
         list=list,
         str=str,
         tuple=tuple,
+        _intstr=int.__str__,
     ):
 
     if _indent is not None and not isinstance(_indent, str):
@@ -309,10 +309,10 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
                 # Subclasses of int/float may override __str__, but we still
                 # want to encode them as integers/floats in JSON. One example
                 # within the standard library is IntEnum.
-                yield buf + str(int(value))
+                yield buf + _intstr(value)
             elif isinstance(value, float):
                 # see comment above for int
-                yield buf + _floatstr(float(value))
+                yield buf + _floatstr(value)
             else:
                 yield buf
                 if isinstance(value, (list, tuple)):
@@ -359,7 +359,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
             # also allow them.  Many encoders seem to do something like this.
             elif isinstance(key, float):
                 # see comment for int/float in _make_iterencode
-                key = _floatstr(float(key))
+                key = _floatstr(key)
             elif key is True:
                 key = 'true'
             elif key is False:
@@ -368,7 +368,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
                 key = 'null'
             elif isinstance(key, int):
                 # see comment for int/float in _make_iterencode
-                key = str(int(key))
+                key = _intstr(key)
             elif _skipkeys:
                 continue
             else:
@@ -389,10 +389,10 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
                 yield 'false'
             elif isinstance(value, int):
                 # see comment for int/float in _make_iterencode
-                yield str(int(value))
+                yield _intstr(value)
             elif isinstance(value, float):
                 # see comment for int/float in _make_iterencode
-                yield _floatstr(float(value))
+                yield _floatstr(value)
             else:
                 if isinstance(value, (list, tuple)):
                     chunks = _iterencode_list(value, _current_indent_level)
@@ -419,10 +419,10 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
             yield 'false'
         elif isinstance(o, int):
             # see comment for int/float in _make_iterencode
-            yield str(int(o))
+            yield _intstr(o)
         elif isinstance(o, float):
             # see comment for int/float in _make_iterencode
-            yield _floatstr(float(o))
+            yield _floatstr(o)
         elif isinstance(o, (list, tuple)):
             yield from _iterencode_list(o, _current_indent_level)
         elif isinstance(o, dict):
index f63d758348d3681a792daf0ef82a9c089c1dc74f..f82af347cbb3e98adcb3ca1384b9c56c37cda7a1 100644 (file)
@@ -116,8 +116,6 @@ raise_errmsg(char *msg, PyObject *s, Py_ssize_t end);
 static PyObject *
 encoder_encode_string(PyEncoderObject *s, PyObject *obj);
 static PyObject *
-encoder_encode_long(PyEncoderObject* s UNUSED, PyObject *obj);
-static PyObject *
 encoder_encode_float(PyEncoderObject *s, PyObject *obj);
 
 #define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '"')
@@ -1444,39 +1442,10 @@ _encoded_const(PyObject *obj)
     }
 }
 
-static PyObject *
-encoder_encode_long(PyEncoderObject* s UNUSED, PyObject *obj)
-{
-    /* Return the JSON representation of a PyLong and PyLong subclasses.
-       Calls int() on PyLong subclasses in case the str() was changed.
-       Added specifically to deal with IntEnum.  See Issue18264. */
-    PyObject *encoded, *longobj;
-    if (PyLong_CheckExact(obj)) {
-        encoded = PyObject_Str(obj);
-    }
-    else {
-        longobj = PyNumber_Long(obj);
-        if (longobj == NULL) {
-            PyErr_SetString(
-                    PyExc_ValueError,
-                    "Unable to coerce int subclass to int"
-                    );
-            return NULL;
-        }
-        encoded = PyObject_Str(longobj);
-        Py_DECREF(longobj);
-    }
-    return encoded;
-}
-
-
 static PyObject *
 encoder_encode_float(PyEncoderObject *s, PyObject *obj)
 {
-    /* Return the JSON representation of a PyFloat.
-       Modified to call float() on float subclasses in case the subclass
-       changes the repr.  See Issue18264.  */
-    PyObject *encoded, *floatobj;
+    /* Return the JSON representation of a PyFloat. */
     double i = PyFloat_AS_DOUBLE(obj);
     if (!Py_IS_FINITE(i)) {
         if (!s->allow_nan) {
@@ -1496,24 +1465,7 @@ encoder_encode_float(PyEncoderObject *s, PyObject *obj)
             return PyUnicode_FromString("NaN");
         }
     }
-    /* coerce float subclasses to float (primarily for Enum) */
-    if (PyFloat_CheckExact(obj)) {
-        /* Use a better float format here? */
-        encoded = PyObject_Repr(obj);
-    }
-    else {
-        floatobj = PyNumber_Float(obj);
-        if (floatobj == NULL) {
-            PyErr_SetString(
-                    PyExc_ValueError,
-                    "Unable to coerce float subclass to float"
-                    );
-            return NULL;
-        }
-        encoded = PyObject_Repr(floatobj);
-        Py_DECREF(floatobj);
-    }
-    return encoded;
+    return PyFloat_Type.tp_repr(obj);
 }
 
 static PyObject *
@@ -1557,7 +1509,7 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
         return _steal_accumulate(acc, encoded);
     }
     else if (PyLong_Check(obj)) {
-        PyObject *encoded = encoder_encode_long(s, obj);
+        PyObject *encoded = PyLong_Type.tp_str(obj);
         if (encoded == NULL)
             return -1;
         return _steal_accumulate(acc, encoded);
@@ -1722,7 +1674,7 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
                 goto bail;
         }
         else if (PyLong_Check(key)) {
-            kstr = encoder_encode_long(s, key);
+            kstr = PyLong_Type.tp_str(key);
             if (kstr == NULL) {
                 goto bail;
             }