DEV Community

Marvin
Marvin

Posted on • Edited on

Python's print and the flush parameter.

Overview

If you've been in touch with the Python community relatively recently, you've probably heard of rich. rich brings colors to the terminal... without much of a hassle.

These two lines show rich.print overriding Python's built-in print function. One thing that caught my attention is rich.print's docstring, especially this line:

flush (bool, optional): Has no effect as Rich always flushes output. Defaults to False.

I seldomly use this parameter. But I do remember one place where I've seen it — pyautogui's mouse documentation where Al Sweigart gave this code example which shows the coordinates of your cursor:

    #! python3
    import pyautogui, sys
    print('Press Ctrl-C to quit.')
    try:
        while True:
            x, y = pyautogui.position()
            positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4)
            print(positionStr, end='')
            print('\b' * len(positionStr), end='', flush=True)
        except KeyboardInterrupt:
            print('\n')
Enter fullscreen mode Exit fullscreen mode

So, really. What does flush do?

What does flush do?

Without further circumlocutions, let's go ahead and run this script.

flush does not affect the output. What it changes is the manner in which it is printed.

Here are my findings:

  • flush=False (yes, the default) will wait for the line to complete before printing it.
  • flush=True will force our terminal to print it.
  • flush does not matter if end=\n.

Now this begs the question, why? If I have end='', why do I have to explicitly set flush=True?

print, sys.stdout, and PYTHONUNBUFFERED

Below is the first sentence from Python's print documentation:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
Print objects to the text stream file, separated by sep and followed by end.

To be honest, when I first wrote my Hello World program in Python, I didn't go through the documentation to get awed by its implementation. Now that I've seen it, I can infer that the terminal output is a "text stream" which is sys.stdout by default.

From the docs:

stdout is used for the output of print() and expression statements and for the prompts of input()...

These streams are regular text files like those returned by the open() function...

When interactive, the stdout stream is line-buffered. Otherwise, it is block-buffered like regular text files. You can make both streams unbuffered by passing the -u command-line option or setting the PYTHONUNBUFFERED environment variable.

There's apparently a deep rabbit-hole to dig into this. More experienced programmers will probably recognize PYTHONUNBUFFERED in their Dockerfiles. We also probably want to know what's the difference between line-buffered and block-buffered. Personally, I was aware of sys.stdout.write existing.

But for now, we can be comfortable knowing that terminal output is pretty much like a regular text file being read from somewhere. Hence, it makes sense that print, by default, would prefer to complete a line first before giving an output.

But how does this affect flush?

  • Setting PYTHONUNBUFFERED via command line. I use Windows so in PowerShell, it's something like $env:PYTHONUNBUFFERED = "TRUE". This overrides flush=False. It also overrides os.unsetenv.
  • The os module (i.e., os.environ['PYTHONUNBUFFERED'] = "TRUE") does NOT override flush=False.
  • Via python -u flag. The -u flag overrides flush=False regardless of PYTHONUNBUFFERED value.

Now what?

Let us go back to Al Sweigart's mouse code. This line is really interesting:

print('\b' * len(positionStr), end='', flush=True)
Enter fullscreen mode Exit fullscreen mode

Spoiler alert: you may delete the flush=True keyword argument. The character \b is backspace and already enough to delete positionStr. It's probably there only to show some parallelism between this and the Python 2 code right beneath it. Nevertheless, you may play with this line — change end, modify len(positionStr), you may even change the loop.

But what would flush do here? Hopefully, this article has given you the first step in the right direction.

List of links

Top comments (0)