Reputation: 1529
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?
Upvotes: 1
Views: 1777
Reputation: 213807
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.
Upvotes: 4
Reputation: 107095
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)
Upvotes: 3
Reputation: 45562
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)
Upvotes: 0