Redefining Python's Print() Function
Every novice Pythonista is familiar with the trusty built-in function print()
. Its job is simple: output the string representation of an object or expression.
But let’s say you want to change the behavior of print. Instead of sending its output to the terminal, let’s send that output to a file on the disk. We can accomplish this by redefining the print
variable.
Printing to a File
The full function signature of print is:
Note the third keyword argument, file
. The default value of file
is sys.stdout
, which represents the terminal output buffer. The only real requirement for the object passed as file
is that it has a .write()
method. You know what has a write method? File handlers.
Let’s redefine the print variable to instead be a wrapper function around the vanilla built-in print()
. The wrapped print()
needs to be referenced through the builtins
module so that we don’t define a recursive function.
Now, when we call print()
, no output is displayed in the terminal. However, if we read the contents of log.txt
, we can see that our redefined print()
has written to the file.
Print as a Buffer Object
Let’s make it weird. We can actually redefine print()
to be a buffer object that stores all the strings that are passed to it for printing. Instead of a function, print
will be an instance of a class that inherits io.StringIO
.
StringIO
is a in-memory text buffer that works similarly to a file handler. In fact, file handlers and StringIO
both implement the abstract base class IOBase
, which means they have many of the same methods defined.
Here’s a simple example of how to use StringIO
:
Let’s define a new subclass of StringIO
called PrintWrapper
. We’re also going to define a __call__
magic method on this new class. __call__
allows you to define how an instance of a class behaves when it is called like a function.
Strings that you have printed are seperated by \n
when you call print.getvalue(), but you can define a different seperator by passing it as a string to the end=
keyword argument of builtins.print()
.
Conclusion
Why would you ever want to do any of this? Let’s say you are building a web-based programming environment like CoderPad. When a user calls print()
, you wouldn’t want the Python interpreter running on the server to send the printed statement to stdout. You want it outputted to a handler that transmits it to the user’s browser over the Internet. There are probably other ways to accomplish this, but redefining print()
behind the scenes is one possibility.
Edit: As Reddit user Dasher38 points out, there’s a context manager in the standard library contextlib.redirect_stdout
that is better suited for redirecting the output of a web-based programming environment backend. redirect_stdout
redirects everything sent to sys.stdout
(including printed statements) to a specified file-like object.
This is the first of a series of blog entries I’m calling “baby snakes”, bits of Python arcana aimed at intermediate and advanced Python developers. Check back soon for more!