Have you used any command line program which represents its progress by displaying a dynamic progress bar in console? Think about Git, a popular version control system, when using git clone to fetch a repository, you will find that it's updating the downloading progress all the time.
The first program I wrote in my life is "Hello world" (maybe everyone is same as me, lol). I found that after "Hello world" text is outputted to console, the cursor moves to the end of line. Since then, I thought once text is outputted to console, it cannot be updated anymore. But later I found such dynamic progress bar (see above image), it's really amazing!
But how can we make one by our own hands? The key is to use the control character "\r", it's called Carriage Return.
Carriage Return is used to reset cursor's position to the beginning of line. Imagine we print "Hello" first, then we use Carriage Return to reset cursor's position to beginning of line, and print "world" next. What we will see in console is "world" replaced "Hello". To implement our thoughts, we wrote following code:
1 2 3 4 |
import sys sys.stdout.write('Hello') sys.stdout.write('\rworld') |
You may tell me running above code only display "world" in the console, and most importantly you didn't see that "world" is replacing "Hello". Well, actually that happens, just because the progress is too fast, your eyes cannot capture it:)
What we need do is let program blocks for some time after "Hello" is printed on console. time.sleep() function will make current thread sleep for specified number of seconds. So the improved code is following:
1 2 3 4 5 6 |
import sys import time sys.stdout.write('Hello') time.sleep(0.5) sys.stdout.write('\rworld') |
Now you can see "world" is replacing "Hello". You may ask me why not use "print" statement? Because print will send newline to console, we will not use it.
Next is the real progress bar. Progress bar is consisted of a bar which is increasing by time and a value indicates the progress. So let's focus on the "bar" first
1 2 3 4 5 6 |
import sys import time for i in range(30): sys.stdout.write('\r[{0}{1}]'.format('#'*i, ' '*(30-i))) time.sleep(0.1) |
Combining it with progress "value", we got a progress bar
1 2 3 4 5 6 |
import sys import time for i in range(100): sys.stdout.write('\r[{0}{1}] {2}'.format('#'*(i/10), ' '*(10-i/10), i)) time.sleep(0.1) |