4

I'm trying override my last print with a new line but I can't clear the last line.

I thought that flush would clear the line, but I can't see it has any effect.

import time

s = "qwertyuiopåasdfghjklæøzxccvbnm"

for num in range(len(s)):
    print("\r{}".format(str[:len(s)-num]), end="", flush=True)
    time.sleep(.1)

Here in my example, I end up with the output:

qwertyuiopåasdfghjklæøzxccvbnm

But wanted the output to be "q" only. If the next print is smaller than the first line I can still see the end of the last line.

I could just override the first line with spaces, but I don't like that because if I then resize the console, it will shift everything around.

Is there anyway to really clear the last line and only the last line?

a solution that works both in linux and windows would be great.

Thanks.

supremebot
  • 43
  • 4
  • check the answer here https://stackoverflow.com/questions/4897359/output-to-the-same-line-overwriting-previous-output-python-2-5 – Ahmed Ghazey Dec 28 '17 at 22:17

2 Answers2

2

You can use format to pad the string with whitespace, which will overwrite the old text.

import time
s = "qwertyuiopåasdfghjklæøzxccvbnm"

spacer = '\r{{:{}}}'.format(len(s)) # '\r{:30}' for this s

for num in range(len(s), 0, -1):
    print(spacer.format(s[:num]), end='')
    time.sleep(.1)

print()

You can read more about the Format Specification Mini-Language here

Patrick Haugh
  • 49,982
  • 11
  • 66
  • 73
  • Why not just `' ' * (len(s) - num)`? – Dan Dec 28 '17 at 22:38
  • @Dan I guess you could do `print(s[:num] + ' ' * (len(s) - num))`. I don't see that as much better. If the `'{{:{}}}'.format(len(s))` is confusing, I suppose you could do `'{:' + str(len(s)) + '}'` – Patrick Haugh Dec 28 '17 at 22:48
  • your code does not end with "q" at the end of the loop like i wanted because of your end="\r". but i see what you mean. i would still use my code and do `ns = s[:len(s) - num]` and `print("\r{:{}}".format(ns, len(ns)+1), end="", flush=True)` – supremebot Dec 29 '17 at 00:58
0

A more reusable solution could be:

from os import get_terminal_size

def rprint(*args, **kwargs):
    try:
        cols, rows = get_terminal_size()
    except OSError:
        # If get_terminal_size is not supported, override with whitespaces is not needed.
        cols, rows = (1, 1)

    # Override the line with whitespace and return cursor(-1 because of cursor size)
    print("\r{:>{}}".format("", cols-1), end="\r")
    print(*args, **{**kwargs, **{"end": "", "flush": True}})


if __name__ == '__main__':
    import time

    s = "qwertyuiopåasdfghjklæøzxccvbnmq"

    # I want to end the loop with "q", not an empty string.
    for num in range(len(s)):
        rprint(s[:len(s) - num])
        time.sleep(.1)

    rprint("Override last line again")

Tested only in python 3.5+

But does fail, if the last printed line was larger than the terminal width.

I don't know if there is some way to get the last printed line to stdout? If there is then it would be possible to count the length of that line instead of get_terminal_size.

supremebot
  • 43
  • 4