简体   繁体   中英

sys.stdout.write \r carriage, how to overwrite all characters?

I'm playing with itertools.cycle and I'm using a simple list as input. Then I write a while loop and I want to basically overwrite my output with each color as I iterate through them. The sys.stdout.write('\\r' + colors) line does not overwrite all characters, only the length of the string of the next color. Lastly, I have a .5 second delay between each iteration.

import itertools
import time
colors = ['green', 'yellow', 'red']
traffic_light = itertools.cycle(colors)
while True:
    sys.stdout.write('\r' + next(traffic_light))
    sys.stdout.flush()
    time.sleep(.5)

When I get to 'yellow' in my loop, I am left with 'w' or 'low' when the shorter 'green' and 'red' strings are printed. My output looks like this (after the first loop when 'yellow' is printed).

redlow
greenw
yellow

Can I completely overwrite the output with the '\\r' carriage?

The carriage return '\\r' will send the cursor to the beginning of the line, where it can overwrite the existing text. You can combine this with the sequence CSI K, which erases from the current cursor to the end of the line.

Just replace \\r with \\r\\x1b[K . See ANSI escape code .

import itertools
import sys
import time
colors = ['green', 'yellow', 'red']
traffic_light = itertools.cycle(colors)
while True:
    sys.stdout.write('\r\x1b[K' + next(traffic_light))
    sys.stdout.flush()
    time.sleep(.5)

Try out these additional escape sequences:

# Add color
colors = ['\x1b[32mgreen', '\x1b[33myellow', '\x1b[31mred']

Note the limitations of this technique... if the terminal is short enough that your text wraps, the program will move forward one line every time you print. If you need something more robust, curses gives you more power but it doesn't work out of the box on Windows.

You can calculate the maximum width of the color strings and then use str.ljust to pad the output with enough spaces to fill to the maximum width:

import itertools
import time
import sys
colors = ['green', 'yellow', 'red']
traffic_light = itertools.cycle(colors)
max_width = max(map(len, colors))
while True:
    sys.stdout.write('\r' + next(traffic_light).ljust(max_width))
    sys.stdout.flush()
    time.sleep(.5)

Create a format string that left justifies to the max width.

import itertools
import time

colors = ['green', 'yellow', 'red']
fmt = f'\r{{:<{max(map(len, colors))}}}' # fmt = '{:<7}'

for color in itertools.cycle(colors):
    print(fmt.format(color), end='') # if needed add: flush=True
    time.sleep(.5)

Prior to 3.6 use fmt = '\\r{{:<{}}}'.format(max(map(len, colors))) .

Alternatively use the .ljust() string method:

import itertools
import time

colors = ['green', 'yellow', 'red']
width = max(map(len, colors))

for color in itertools.cycle(colors):
    print('\r' + color.ljust(width), end='') # if needed add: flush=True
    time.sleep(.5)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM