felix001
felix001

Reputation: 16691

Printing to same line using While loop in Python

Im trying to get the following output from a while loop to show the progress.

  - ########

Below is the code,

print '  - #',
x = 1
while x < 15:
    print '#',
    time.sleep(0.5)
    x += 1

But Im just getting all of the hashs printed once the while loop is complete (?)

Any ideas

Upvotes: 2

Views: 4147

Answers (5)

Sharad
Sharad

Reputation: 2003

There are plenty of methods to this.

  1. If you are working with Python 2.X, you need to call sys.stdout.flush() after every print.

  2. If you are using python 3 then you can get it done by doing

    print(#,sep = ' ', flush=True)

  3. You can disable the buffering completely if you run python with -u option: python -u script.py

    If you run your script directly i.e. ./script.py then specify it in the shebang line: #!/usr/bin/env python -u.

  4. The other way to do it is to set env variable PYTHONUNBUFFERED from the bash shell: export PYTHONUNBUFFERED="aa"

Adding more details to cause of the issue:

Stdout in Python is line buffered. Meaning if you had skipped the "," in your print your output will be printed as expected. But when the output is printed in the same line then it will be flushed only if there is a new line or the buffer is full. In case you redirect your output to a file instead of terminal (python script.py >output), output will be flushed only when the buffer is full. This can be verified if you pipe the output to cat: python script.py | cat

In all the methods mentioned in this answer and other answers we are explicitly telling Python to not buffer but flush the output as soon as it gets it.

More research on the topic:

This behavior is not Python Specific. This is the case with printf in C as well. It is due to glibc implementation of linux. The reasoning behind this behavior is efficiency. Because the output is buffered number of read and write operations are minimized. I found this article which gives a brief description of the same: Unix Buffering Delays

Upvotes: 4

zondo
zondo

Reputation: 20336

print by default writes to stdout which is stored in sys.stdout. Stdout is flushed when a new line is printed. Since you aren't printing the new line, the text isn't displayed until you do. You can, however, flush stdout yourself:

import sys
import time
print '  - #',
sys.stdout.flush()
x = 1
while x < 15:
    print '#',
    sys.stdout.flush()
    time.sleep(0.5)
    x += 1

You really don't need a while loop. A for loop would be shorter:

import sys
import time
print '  - #',
sys.stdout.flush()
x = 1
for _ in range(15):
    print '#',
    sys.stdout.flush()
    time.sleep(0.5)

Upvotes: 2

jDo
jDo

Reputation: 4010

I think you already got your answer but in case you later want to overwrite the same line, add a carriage return \r before the characters you're printing (to return your typewriter's carriage to the start of the current line, of course ;) ). I use this to have my file processing scripts write to the same line - each new line overwriting the last. Some fiddling with additonal white space is necessary if the new line is shorter than the previous.

Eg. to make a rotating loader thingy that's eventually replaced by a growing line of #s:

import sys
import time

# rotating loader "animation"
# Ubuntu or the aptitude package manager uses something similar
x = 1
symbols = ["|", "/", "-", "\\"]
while x < 20:
    x+=1
    sys.stdout.write("\r" + symbols[x%len(symbols)])
    sys.stdout.flush()
    time.sleep(0.2)


# progress bar "animation" using hashtags 
x = 1
sys.stdout.write("\r")
while x < 10:
    x+=1
    sys.stdout.write('#')
    sys.stdout.flush()
    time.sleep(0.2)

print("")

Upvotes: 2

DevShark
DevShark

Reputation: 9112

Have a look at tqdm. It displays for you a good looking progress bar very easily.

from tqdm import tqdm
for i in tqdm(range(9)):
    ...

Upvotes: 0

Zagfai
Zagfai

Reputation: 428

import sys
import time
while True:
    sys.stdout.write('#')
    sys.stdout.flush()
    time.sleep(0.5)

Upvotes: 5

Related Questions