Skip to content

Commit e0805cf

Browse files
Issue #26719: More efficient formatting of ints and floats in json.
1 parent fc43511 commit e0805cf

File tree

2 files changed

+14
-62
lines changed

2 files changed

+14
-62
lines changed

Lib/json/encoder.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
#ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
3333

3434
INFINITY = float('inf')
35-
FLOAT_REPR = repr
3635

3736
def py_encode_basestring(s):
3837
"""Return a JSON representation of a Python string
@@ -221,7 +220,7 @@ def iterencode(self, o, _one_shot=False):
221220
_encoder = encode_basestring
222221

223222
def floatstr(o, allow_nan=self.allow_nan,
224-
_repr=FLOAT_REPR, _inf=INFINITY, _neginf=-INFINITY):
223+
_repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
225224
# Check for specials. Note that this type of test is processor
226225
# and/or platform-specific, so do tests which don't depend on the
227226
# internals.
@@ -268,6 +267,7 @@ def _make_iterencode(markers, _default, _encoder, _indent, _floatstr,
268267
list=list,
269268
str=str,
270269
tuple=tuple,
270+
_intstr=int.__str__,
271271
):
272272

273273
if _indent is not None and not isinstance(_indent, str):
@@ -309,10 +309,10 @@ def _iterencode_list(lst, _current_indent_level):
309309
# Subclasses of int/float may override __str__, but we still
310310
# want to encode them as integers/floats in JSON. One example
311311
# within the standard library is IntEnum.
312-
yield buf + str(int(value))
312+
yield buf + _intstr(value)
313313
elif isinstance(value, float):
314314
# see comment above for int
315-
yield buf + _floatstr(float(value))
315+
yield buf + _floatstr(value)
316316
else:
317317
yield buf
318318
if isinstance(value, (list, tuple)):
@@ -359,7 +359,7 @@ def _iterencode_dict(dct, _current_indent_level):
359359
# also allow them. Many encoders seem to do something like this.
360360
elif isinstance(key, float):
361361
# see comment for int/float in _make_iterencode
362-
key = _floatstr(float(key))
362+
key = _floatstr(key)
363363
elif key is True:
364364
key = 'true'
365365
elif key is False:
@@ -368,7 +368,7 @@ def _iterencode_dict(dct, _current_indent_level):
368368
key = 'null'
369369
elif isinstance(key, int):
370370
# see comment for int/float in _make_iterencode
371-
key = str(int(key))
371+
key = _intstr(key)
372372
elif _skipkeys:
373373
continue
374374
else:
@@ -389,10 +389,10 @@ def _iterencode_dict(dct, _current_indent_level):
389389
yield 'false'
390390
elif isinstance(value, int):
391391
# see comment for int/float in _make_iterencode
392-
yield str(int(value))
392+
yield _intstr(value)
393393
elif isinstance(value, float):
394394
# see comment for int/float in _make_iterencode
395-
yield _floatstr(float(value))
395+
yield _floatstr(value)
396396
else:
397397
if isinstance(value, (list, tuple)):
398398
chunks = _iterencode_list(value, _current_indent_level)
@@ -419,10 +419,10 @@ def _iterencode(o, _current_indent_level):
419419
yield 'false'
420420
elif isinstance(o, int):
421421
# see comment for int/float in _make_iterencode
422-
yield str(int(o))
422+
yield _intstr(o)
423423
elif isinstance(o, float):
424424
# see comment for int/float in _make_iterencode
425-
yield _floatstr(float(o))
425+
yield _floatstr(o)
426426
elif isinstance(o, (list, tuple)):
427427
yield from _iterencode_list(o, _current_indent_level)
428428
elif isinstance(o, dict):

Modules/_json.c

+4-52
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ raise_errmsg(char *msg, PyObject *s, Py_ssize_t end);
116116
static PyObject *
117117
encoder_encode_string(PyEncoderObject *s, PyObject *obj);
118118
static PyObject *
119-
encoder_encode_long(PyEncoderObject* s UNUSED, PyObject *obj);
120-
static PyObject *
121119
encoder_encode_float(PyEncoderObject *s, PyObject *obj);
122120

123121
#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '"')
@@ -1444,39 +1442,10 @@ _encoded_const(PyObject *obj)
14441442
}
14451443
}
14461444

1447-
static PyObject *
1448-
encoder_encode_long(PyEncoderObject* s UNUSED, PyObject *obj)
1449-
{
1450-
/* Return the JSON representation of a PyLong and PyLong subclasses.
1451-
Calls int() on PyLong subclasses in case the str() was changed.
1452-
Added specifically to deal with IntEnum. See Issue18264. */
1453-
PyObject *encoded, *longobj;
1454-
if (PyLong_CheckExact(obj)) {
1455-
encoded = PyObject_Str(obj);
1456-
}
1457-
else {
1458-
longobj = PyNumber_Long(obj);
1459-
if (longobj == NULL) {
1460-
PyErr_SetString(
1461-
PyExc_ValueError,
1462-
"Unable to coerce int subclass to int"
1463-
);
1464-
return NULL;
1465-
}
1466-
encoded = PyObject_Str(longobj);
1467-
Py_DECREF(longobj);
1468-
}
1469-
return encoded;
1470-
}
1471-
1472-
14731445
static PyObject *
14741446
encoder_encode_float(PyEncoderObject *s, PyObject *obj)
14751447
{
1476-
/* Return the JSON representation of a PyFloat.
1477-
Modified to call float() on float subclasses in case the subclass
1478-
changes the repr. See Issue18264. */
1479-
PyObject *encoded, *floatobj;
1448+
/* Return the JSON representation of a PyFloat. */
14801449
double i = PyFloat_AS_DOUBLE(obj);
14811450
if (!Py_IS_FINITE(i)) {
14821451
if (!s->allow_nan) {
@@ -1496,24 +1465,7 @@ encoder_encode_float(PyEncoderObject *s, PyObject *obj)
14961465
return PyUnicode_FromString("NaN");
14971466
}
14981467
}
1499-
/* coerce float subclasses to float (primarily for Enum) */
1500-
if (PyFloat_CheckExact(obj)) {
1501-
/* Use a better float format here? */
1502-
encoded = PyObject_Repr(obj);
1503-
}
1504-
else {
1505-
floatobj = PyNumber_Float(obj);
1506-
if (floatobj == NULL) {
1507-
PyErr_SetString(
1508-
PyExc_ValueError,
1509-
"Unable to coerce float subclass to float"
1510-
);
1511-
return NULL;
1512-
}
1513-
encoded = PyObject_Repr(floatobj);
1514-
Py_DECREF(floatobj);
1515-
}
1516-
return encoded;
1468+
return PyFloat_Type.tp_repr(obj);
15171469
}
15181470

15191471
static PyObject *
@@ -1557,7 +1509,7 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
15571509
return _steal_accumulate(acc, encoded);
15581510
}
15591511
else if (PyLong_Check(obj)) {
1560-
PyObject *encoded = encoder_encode_long(s, obj);
1512+
PyObject *encoded = PyLong_Type.tp_str(obj);
15611513
if (encoded == NULL)
15621514
return -1;
15631515
return _steal_accumulate(acc, encoded);
@@ -1722,7 +1674,7 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
17221674
goto bail;
17231675
}
17241676
else if (PyLong_Check(key)) {
1725-
kstr = encoder_encode_long(s, key);
1677+
kstr = PyLong_Type.tp_str(key);
17261678
if (kstr == NULL) {
17271679
goto bail;
17281680
}

0 commit comments

Comments
 (0)