Currently, print("a", "b") makes four separate calls to sys.stdout.write():
sys.stdout.write("a")
sys.stdout.write(" ")
sys.stdout.write("b")
sys.stdout.write("\n")
I propose changing print() to combine its output into a single write() call whenever possible:
sys.stdout.write("a b\n")
Motivation
The main benefit is preventing output from concurrent print() calls from being interleaved.
For example, structlog provides two logger implementations:
PrintLoggerusesprint().WriteLoggeruses a singlewrite()call per log message.
When two threads log "msg1" and "msg2" concurrently using PrintLogger, the output can be msg1msg2\n\n instead of msg1\nmsg2\n.
WriteLogger avoids this particular problem by writing each complete log message in one call.
This means users need to understand the internal implementation of Python’s print() function to choose the safer logger for multithreaded applications.
Benefits
- Better behavior with multiple threads: Output from a single
print()call is less likely to be interleaved with output from other threads. - Better performance for small outputs: Combining several writes into one can reduce Python-level calls and I/O overhead.
Drawbacks
- Performance and memory overhead for large outputs: Constructing a combined string requires additional memory and copying, potentially making large outputs slower.
- Changed error behavior: Currently, if converting an argument to a string or writing to the stream raises an exception, earlier arguments may already have been written. With a single write, conversion errors would occur before any output is written.
Questions
- Do you think this change is worth making, given the compatibility and performance trade-offs?
- Would this change require a PEP, or could it be handled through the normal CPython issue and PR process?