From abfa80db6633a3587d32d11ae1adb7425e958d78 Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Mon, 26 Oct 2026 17:01:48 +0000 Subject: [PATCH 1/2] 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 Claude-Session: https://claude.ai/code/session_0129ST3GmU89AvSnUNSXu2Yi --- ...-10-26-04-00-00.gh-issue-160725.pRnT8w.rst | 2 + Python/bltinmodule.c | 65 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst new file mode 100644 index 000000000000000..78813ec04bab6c4 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst @@ -0,0 +1,2 @@ +Speed up :func:`print` by looking up the file's ``write()`` method once per +call. diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 10c5428159e66f9..ab3381746321ec7 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -2241,6 +2241,23 @@ builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp, return PyNumber_Power(base, exp, mod); } +/* Write str(obj) by calling write. */ +static int +print_write(PyObject *write, PyObject *obj) +{ + PyObject *str = PyObject_Str(obj); + if (str == NULL) { + return -1; + } + PyObject *result = PyObject_CallOneArg(write, str); + Py_DECREF(str); + if (result == NULL) { + return -1; + } + Py_DECREF(result); + return 0; +} + /*[clinic input] print as builtin_print @@ -2264,7 +2281,7 @@ builtin_print_impl(PyObject *module, PyObject * const *objects, PyObject *file, int flush) /*[clinic end generated code: output=38d8def56c837bcc input=ff35cb3d59ee8115]*/ { - int i, err; + int i; if (file == Py_None) { file = PySys_GetAttr(&_Py_ID(stdout)); @@ -2283,7 +2300,7 @@ builtin_print_impl(PyObject *module, PyObject * const *objects, } if (sep == Py_None) { - sep = NULL; + sep = _Py_LATIN1_CHR(' '); } else if (sep && !PyUnicode_Check(sep)) { PyErr_Format(PyExc_TypeError, @@ -2293,7 +2310,7 @@ builtin_print_impl(PyObject *module, PyObject * const *objects, return NULL; } if (end == Py_None) { - end = NULL; + end = _Py_LATIN1_CHR('\n'); } else if (end && !PyUnicode_Check(end)) { PyErr_Format(PyExc_TypeError, @@ -2303,36 +2320,23 @@ builtin_print_impl(PyObject *module, PyObject * const *objects, return NULL; } + PyObject *write = PyObject_GetAttr(file, &_Py_ID(write)); + if (write == NULL) { + Py_DECREF(file); + return NULL; + } for (i = 0; i < objects_length; i++) { - if (i > 0) { - if (sep == NULL) { - err = PyFile_WriteString(" ", file); - } - else { - err = PyFile_WriteObject(sep, file, Py_PRINT_RAW); - } - if (err) { - Py_DECREF(file); - return NULL; - } + if (i > 0 && print_write(write, sep) < 0) { + goto error; } - err = PyFile_WriteObject(objects[i], file, Py_PRINT_RAW); - if (err) { - Py_DECREF(file); - return NULL; + if (print_write(write, objects[i]) < 0) { + goto error; } } - - if (end == NULL) { - err = PyFile_WriteString("\n", file); - } - else { - err = PyFile_WriteObject(end, file, Py_PRINT_RAW); - } - if (err) { - Py_DECREF(file); - return NULL; + if (print_write(write, end) < 0) { + goto error; } + Py_DECREF(write); if (flush) { if (_PyFile_Flush(file) < 0) { @@ -2343,6 +2347,11 @@ builtin_print_impl(PyObject *module, PyObject * const *objects, Py_DECREF(file); Py_RETURN_NONE; + +error: + Py_DECREF(write); + Py_DECREF(file); + return NULL; } From d5f09c66239197e2fb4a6249d1c841eb01ff675a Mon Sep 17 00:00:00 2001 From: Cody Maloney Date: Mon, 26 Oct 2026 17:51:47 +0000 Subject: [PATCH 2/2] Link the NEWS entry to the file.write() documentation Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0129ST3GmU89AvSnUNSXu2Yi --- .../2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst index 78813ec04bab6c4..3cd098613e5afa6 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-26-04-00-00.gh-issue-160725.pRnT8w.rst @@ -1,2 +1,2 @@ -Speed up :func:`print` by looking up the file's ``write()`` method once per -call. +Speed up :func:`print` by looking up the file's :meth:`~file.write` method +once per call.