Skip to content

Commit abfa80d

Browse files
cmaloneyclaude
andcommitted
gh-160725: Speed up print() by looking up write() once per call
Look up the file's write() method once per print() call, instead of once for each argument, separator and line ending, and pass the cached ' ' and '\n' strings for the default sep and end directly, instead of converting them from C strings with PyFile_WriteString(). write() is called exactly as before. print() is up to 1.66x faster in pyperf benchmarks, 1.20x geometric mean; for example, print('a', 1, 2.5) to a file goes from 996 ns to 687 ns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0129ST3GmU89AvSnUNSXu2Yi
1 parent 796b26b commit abfa80d

2 files changed

Lines changed: 39 additions & 28 deletions

File tree

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Speed up :func:`print` by looking up the file's ``write()`` method once per
2+
call.

‎Python/bltinmodule.c‎

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2241,6 +2241,23 @@ builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp,
22412241
return PyNumber_Power(base, exp, mod);
22422242
}
22432243

2244+
/* Write str(obj) by calling write. */
2245+
static int
2246+
print_write(PyObject *write, PyObject *obj)
2247+
{
2248+
PyObject *str = PyObject_Str(obj);
2249+
if (str == NULL) {
2250+
return -1;
2251+
}
2252+
PyObject *result = PyObject_CallOneArg(write, str);
2253+
Py_DECREF(str);
2254+
if (result == NULL) {
2255+
return -1;
2256+
}
2257+
Py_DECREF(result);
2258+
return 0;
2259+
}
2260+
22442261
/*[clinic input]
22452262
print as builtin_print
22462263
@@ -2264,7 +2281,7 @@ builtin_print_impl(PyObject *module, PyObject * const *objects,
22642281
PyObject *file, int flush)
22652282
/*[clinic end generated code: output=38d8def56c837bcc input=ff35cb3d59ee8115]*/
22662283
{
2267-
int i, err;
2284+
int i;
22682285

22692286
if (file == Py_None) {
22702287
file = PySys_GetAttr(&_Py_ID(stdout));
@@ -2283,7 +2300,7 @@ builtin_print_impl(PyObject *module, PyObject * const *objects,
22832300
}
22842301

22852302
if (sep == Py_None) {
2286-
sep = NULL;
2303+
sep = _Py_LATIN1_CHR(' ');
22872304
}
22882305
else if (sep && !PyUnicode_Check(sep)) {
22892306
PyErr_Format(PyExc_TypeError,
@@ -2293,7 +2310,7 @@ builtin_print_impl(PyObject *module, PyObject * const *objects,
22932310
return NULL;
22942311
}
22952312
if (end == Py_None) {
2296-
end = NULL;
2313+
end = _Py_LATIN1_CHR('\n');
22972314
}
22982315
else if (end && !PyUnicode_Check(end)) {
22992316
PyErr_Format(PyExc_TypeError,
@@ -2303,36 +2320,23 @@ builtin_print_impl(PyObject *module, PyObject * const *objects,
23032320
return NULL;
23042321
}
23052322

2323+
PyObject *write = PyObject_GetAttr(file, &_Py_ID(write));
2324+
if (write == NULL) {
2325+
Py_DECREF(file);
2326+
return NULL;
2327+
}
23062328
for (i = 0; i < objects_length; i++) {
2307-
if (i > 0) {
2308-
if (sep == NULL) {
2309-
err = PyFile_WriteString(" ", file);
2310-
}
2311-
else {
2312-
err = PyFile_WriteObject(sep, file, Py_PRINT_RAW);
2313-
}
2314-
if (err) {
2315-
Py_DECREF(file);
2316-
return NULL;
2317-
}
2329+
if (i > 0 && print_write(write, sep) < 0) {
2330+
goto error;
23182331
}
2319-
err = PyFile_WriteObject(objects[i], file, Py_PRINT_RAW);
2320-
if (err) {
2321-
Py_DECREF(file);
2322-
return NULL;
2332+
if (print_write(write, objects[i]) < 0) {
2333+
goto error;
23232334
}
23242335
}
2325-
2326-
if (end == NULL) {
2327-
err = PyFile_WriteString("\n", file);
2328-
}
2329-
else {
2330-
err = PyFile_WriteObject(end, file, Py_PRINT_RAW);
2331-
}
2332-
if (err) {
2333-
Py_DECREF(file);
2334-
return NULL;
2336+
if (print_write(write, end) < 0) {
2337+
goto error;
23352338
}
2339+
Py_DECREF(write);
23362340

23372341
if (flush) {
23382342
if (_PyFile_Flush(file) < 0) {
@@ -2343,6 +2347,11 @@ builtin_print_impl(PyObject *module, PyObject * const *objects,
23432347
Py_DECREF(file);
23442348

23452349
Py_RETURN_NONE;
2350+
2351+
error:
2352+
Py_DECREF(write);
2353+
Py_DECREF(file);
2354+
return NULL;
23462355
}
23472356

23482357

0 commit comments

Comments
 (0)