9

So, I'm just recently learning python and I was playing with some code. I wanted to print the some character without line breaks over a loop with some delay. I used the time.sleep() function inside the for loop. But, all it does is delay the output for the total time it would have taken in the loop, all at once and, then print out the character.

I did try it without the "end" attribute and it worked perfectly. But, I didn't want the line break.

from time import sleep
print("starting the progress bar")


for i in range(50):
    sleep(0.1)
    print("#", end = '')

I expected the output to print a character and with a delay, print another character. But, the script delays for 0.1 seconds for 50 times and then prints out all the characters at once

Gino Mempin
  • 25,369
  • 29
  • 96
  • 135
thesuzan
  • 111
  • 1
  • 1
  • 7
  • Are you sure your ```print``` statement is not outside of the for loop? Be careful with indentation – Nic Laforge Jul 05 '19 at 04:58
  • @NicLaforge Yes, there are no indentation mistakes in the code. – thesuzan Jul 05 '19 at 05:02
  • Not sure why @tawab_shakeel modified your code in the question, as he edited with the proper answer. I have looked at your original code and your print was outside the loop – Nic Laforge Jul 05 '19 at 05:02
  • @NicLaforge i just put the code in code block otherwise the question was not in a readable format – tawab_shakeel Jul 05 '19 at 05:04
  • @thesuzan you have option not to accept the edit if you feel the edit is not properly done by any other user – tawab_shakeel Jul 05 '19 at 05:06
  • @NicLaforge I assure you that there are no indentation mistakes. You can trust me on that. – thesuzan Jul 05 '19 at 05:07
  • @tawab_shakeel, I understand the code block, but you also changed the format as original format was ```for i in range(50): sleep(0.1)```. A oneliner which is valid in python. That would explain why the ```print``` is executed at the end. – Nic Laforge Jul 05 '19 at 05:07
  • @tawab_shakeel Your edit was what I initially intended to put in the question. I just forgot to format the code. – thesuzan Jul 05 '19 at 05:08
  • @thesuzan, so if you copy past the edited code block, it still does not work? I have tried it and it works. – Nic Laforge Jul 05 '19 at 05:08
  • @NicLaforge I tried the edited part too, didn't work it waited first and then printed – Amartya Gaur Jul 05 '19 at 05:11
  • @NicLaforge No, the delay happens first then it prints the characters all at once without any delay. – thesuzan Jul 05 '19 at 05:12
  • That's what I meant – Amartya Gaur Jul 05 '19 at 05:14
  • It works if you remove the end="0" – Amartya Gaur Jul 05 '19 at 05:15
  • I am speechless about this as I dont see why it would not work. I do believe you about your indentation is correct, but would you mind trying my solution below which will move it inside a method just to confirming more.. let me know – Nic Laforge Jul 05 '19 at 05:20
  • @AmartyaGaur , yes. But I don't want the line to break every time it loops – thesuzan Jul 05 '19 at 05:20
  • Please try and confirm with the below answer code. If it does not work, can you provide how you run it and which python version you are using – Nic Laforge Jul 05 '19 at 05:23
  • Possible duplicate of [How to flush output of print function?](https://stackoverflow.com/questions/230751/how-to-flush-output-of-print-function) – MisterMiyagi Jul 05 '19 at 05:40

4 Answers4

11

As python is linebuffered it will wait for a newline before printing the stdout.

Solution 1:

Add PYTHONUNBUFFERED=1 to your env.var:

export PYTHONUNBUFFERED=1

This will allow the output to be immediately dumped

Solution 2:

As you are using python >= 3 you can use the flush=True

for i in range(50):
    sleep(0.1)
    print("#", end="", flush=True)
Nic Laforge
  • 1,776
  • 1
  • 8
  • 14
  • This doesn't change anything. I get the same result; the delay first, and then the characters are printed, without any delay in between. – thesuzan Jul 05 '19 at 05:25
  • Are you running from terminal? – Nic Laforge Jul 05 '19 at 05:26
  • I'm using a linux subsystem on windows to run the code with Python 3.6.7. But, I also tried it on the anaconda prompt with Python 3.7.3. Both gave me the same results – thesuzan Jul 05 '19 at 05:28
  • I don't understand that. Do I add "export PYTHONUNBUFFERED=1" at the beginning of my code? That gives me an error. – thesuzan Jul 05 '19 at 05:34
  • No run it from the terminal before calling your code. Or even better set it in your bashrc file so it remains – Nic Laforge Jul 05 '19 at 05:35
  • Try with the flush parameter – Nic Laforge Jul 05 '19 at 05:41
  • Thanks, that worked. Would you care to help me understand why. – thesuzan Jul 05 '19 at 05:46
  • Ok good! I explain that by setting the PYTHONUNBUFFERED=1 the output would be immediately dumped. Python by default is linebuffered. Therefore it will wait for a new line to print the output. Using ```flush```, it will dump the output right away. If you always want this behaviour, you can set the env.v. – Nic Laforge Jul 05 '19 at 05:49
1

By default, Python is linebuffered. As long as you print without a newline, output is collected but not shown. You must forcefully flush the output.

from time import sleep
print("starting the progress bar")


for i in range(50):
    sleep(0.1)
    print("#", end = '', flush=True)

Note in that whatever you use to view the output might be linebuffered as well. This cannot be changed from within your script.

MisterMiyagi
  • 44,374
  • 10
  • 104
  • 119
1

I just found a solution on reddit.

reddit comment on why it doesn't work and how beginners fall into the same pitfall

So, it has something to do with buffering.

Here's the code that would work;

from time import sleep
print("starting the progress bar")


for i in range(50):
    sleep(0.1)
    print("#", end = '', flush = True)
thesuzan
  • 111
  • 1
  • 1
  • 7
1

You can use the -u option when running your program.

$ man python3


PYTHON(1)                                                            PYTHON(1)

...

       -u     Force  the  stdout  and  stderr  streams to be unbuffered.  This
              option has no effect on the stdin stream.

Run like this: python3 -u file.py


Alternatively, you can set the PYTHONUNBUFFERED environment variable in your shell

       PYTHONUNBUFFERED
              If this is set to a non-empty string it is equivalent to  speci-
              fying the -u option.

Like so: PYTHONUNBUFFERED="yes" python3 file.py


Lastly, you can use flush=True as other answers have mentioned.

xrisk
  • 3,790
  • 22
  • 45