119

Basically I want to do the opposite of what this guy did... hehe.

Python Script: Print new line each time to shell rather than update existing line

I have a program that is telling me how far along it is.

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete"

So if len(some_list) was 50, I'd get that last line printed 50 times over. I want to print one line and keep updating that line. I know I know this is probably the lamest question you'll read all day. I just can't figure out the four words I need to put into google to get the answer.

Update! I tried mvds' suggestion which SEEMED right. The new code

print percent_complete,"           \r",

Percent complete is just a string (I was abstracting the first time now I an trying to be literal). The result now is that it runs the program, doesn't print ANYTHING until after the program is over, and then prints "100 percent complete" on one and only one line.

Without the carriage return (but with the comma, half of mvds' suggestion) it prints nothing until the end. And then prints:

0 percent complete     2 percent complete     3 percent complete     4 percent complete    

And so on. So now the new issue is that with the comma it doesn't print until the program is finished.

With the carriage return and no comma it behaves the exact same as with neither.

3
  • You might want to also check sys.stdout.isatty() so you don't spit these things out when not running in a terminal. Commented Aug 5, 2010 at 23:50
  • I am running this from a terminal... good thought though. I'm sure I'll need that at some point. Commented Aug 6, 2010 at 0:17
  • 1
    the background is, btw, that in several languages the \n (which we now omit) serves as an implicit signal to flush to stdout. For otherwise a lot of people will be confused. Commented Aug 6, 2010 at 0:24

19 Answers 19

94

It's called the carriage return, or \r

Use

print i/len(some_list)*100," percent complete         \r",

The comma prevents print from adding a newline. (and the spaces will keep the line clear from prior output)

Also, don't forget to terminate with a print "" to get at least a finalizing newline!

Sign up to request clarification or add additional context in comments.

7 Comments

Just make sure you're always printing the same amount of data (or more than any previous print) to the line, otherwise you'll end up with cruft at the end.
So close... I'll update the question with the result of this.
@dustynachos: Heh, forgot about that wrinkle. See the Python Output Buffering question: stackoverflow.com/questions/107705/python-output-buffering
@dustynachos: (or just use sys.stdout.flush() after each print call, that may actually be better if you don't care about output buffering for the rest of your program)
this doesn't work for me. I've actually tried this numerous times and it has never worked for me. I'm using iterm2 on a mac, but i'm ssh'd into a linux server most of the time. I've never found a method to do this that actually works.
|
51

In Python 3.3+ you don’t need sys.stdout.flush(). print(string, end='', flush=True) works.

So

print('foo', end='')
print('\rbar', end='', flush=True)

will overwrite ‘foo’ with ‘bar’.

2 Comments

It works, provided the printed text ends with a "\r".
works perfectly with localhost terminal, and thru SSH
47

For me, what worked was a combo of Remi's and siriusd's answers:

from __future__ import print_function
import sys

print(str, end='\r')
sys.stdout.flush()

2 Comments

Outdated.. As of Python 3.8.5 for me only that works: print("some string", end='\r')
It works for me in debug run but not on normal run without debugger, very strange.. As it would not flush but it should.
44

From python 3.x you can do:

print('bla bla', end='')

(which can also be used in Python 2.6 or 2.7 by putting from __future__ import print_function at the top of your script/module)

Python console progressbar example:

import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    n=0
    while n<total:
        done = '#'*(n+1)
        todo = '-'*(total-n-1)
        s = '<{0}>'.format(done+todo)
        if not todo:
            s+='\n'        
        if n>0:
            s = '\r'+s
        print(s, end='')
        yield n
        n+=1

# example for use of status generator
for i in range_with_status(10):
    time.sleep(0.1)

3 Comments

The \r appears to add a new line as well
this gets rid of the newline, but does not allow overwriting, which I think is what the author wants.
@bgenchel used with '\r' (as in code sample) it does exactly what OP wants
14

Late to the game - but since the none of the answers worked for me (I didn't try them all) and I've come upon this answer more than once in my search ... In python 3, this solution is pretty elegant and I believe does exactly what the author is looking for, it updates a single statement on the same line. Note, you may have to do something special if the line shrinks instead of grows (like perhaps make the string a fixed length with padded spaces at the end)

if __name__ == '__main__':
    for i in range(100):
        print("", end=f"\rPercentComplete: {i} %")
        time.sleep(0.2)

2 Comments

simplest and cleanest option for python => 3.6
This was the only thing that worked when running a script in the PyCharm IDE. print(value, end="\r") worked in the interactive console, but not the actual command line output. Flushing didn't help either.
13

for Console you'll probably need

sys.stdout.flush()

to force update. I think using , in print will block stdout from flushing and somehow it won't update

1 Comment

Terminator was only refreshing the line every 30 seconds when using print("...", end='\r') for me unless I ran this command immediately after the print statement. Thanks
7

As of end of 2020 and Python 3.8.5 on linux console for me only this works:

print('some string', end='\r')

Credit goes to: This post

Comments

5

As of 2021, for Python 3.9.0 the following solution worked for me in Windows 10, Pycharm.

print('\r some string ', end='', flush=True)

1 Comment

works on mac m1
4

If you are using Spyder, the lines just print continuously with all the previous solutions. A way to avoid that is using:

for i in range(1000):
    print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
    sys.stdout.flush()

1 Comment

This was the only working solution for me (Python 3.8, Windows, PyCharm).
3

This works for me, hacked it once to see if it is possible, but never actually used in my program (GUI is so much nicer):

import time
f = '%4i %%'
len_to_clear = len(f)+1
clear = '\x08'* len_to_clear
print 'Progress in percent:'+' '*(len_to_clear),
for i in range(123):
    print clear+f % (i*100//123),
    time.sleep(0.4)
raw_input('\nDone')

Comments

3
import time
import sys


def update_pct(w_str):
    w_str = str(w_str)
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(" " * len(w_str))
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(w_str)
    sys.stdout.flush()

for pct in range(0, 101):
    update_pct("{n}%".format(n=str(pct)))
    time.sleep(0.1)

\b will move the location of the cursor back one space
So we move it back all the way to the beginning of the line
We then write spaces to clear the current line - as we write spaces the cursor moves forward/right by one
So then we have to move the cursor back at the beginning of the line before we write our new data

Tested on Windows cmd using Python 2.7

Comments

2

In those cases, with python 3.x, I'm using the following code:

for ii in range(100):
    print(f"\rPercent: {ii+1} %", end=" "*20)

The problem with some other answers is that if your printed string goes shorter at one step, the last characters from the previous string won't be overwrited.

So I use end=" "*20 in order to overwrite the previous line with whitespace. Just make sure that 20 is longer than the length of your longest string.

Comments

1

Try it like this:

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete",

(With a comma at the end.)

1 Comment

This just appends the new text to the old (functionally similar but ugly).
1

For Python 3+

for i in range(5):
    print(str(i) + '\r', sep='', end ='', file = sys.stdout , flush = False)

Comments

0

Based on Remi answer for Python 2.7+ use this:

from __future__ import print_function
import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    import sys
    n = 0
    while n < total:
        done = '#' * (n + 1)
        todo = '-' * (total - n - 1)
        s = '<{0}>'.format(done + todo)
        if not todo:
            s += '\n'
        if n > 0:
            s = '\r' + s
        print(s, end='\r')
        sys.stdout.flush()
        yield n
        n += 1


# example for use of status generator
for i in range_with_status(50):
    time.sleep(0.2)

Comments

0

For Python 3.6+ and for any list rather than just ints, as well as using the entire width of your console window and not crossing over to a new line, you could use the following:

note: please be informed, that the function get_console_with() will work only on Linux based systems, and as such you have to rewrite it to work on Windows.

import os
import time

def get_console_width():
    """Returns the width of console.

    NOTE: The below implementation works only on Linux-based operating systems.
    If you wish to use it on another OS, please make sure to modify it appropriately.
    """
    return int(os.popen('stty size', 'r').read().split()[1])


def range_with_progress(list_of_elements):
    """Iterate through list with a progress bar shown in console."""

    # Get the total number of elements of the given list.
    total = len(list_of_elements)
    # Get the width of currently used console. Subtract 2 from the value for the
    # edge characters "[" and "]"
    max_width = get_console_width() - 2
    # Start iterating over the list.
    for index, element in enumerate(list_of_elements):
        # Compute how many characters should be printed as "done". It is simply
        # a percentage of work done multiplied by the width of the console. That
        # is: if we're on element 50 out of 100, that means we're 50% done, or
        # 0.5, and we should mark half of the entire console as "done".
        done = int(index / total * max_width)
        # Whatever is left, should be printed as "unfinished"
        remaining = max_width - done
        # Print to the console.
        print(f'[{done * "#"}{remaining * "."}]', end='\r')
        # yield the element to work with it
        yield element
    # Finally, print the full line. If you wish, you can also print whitespace
    # so that the progress bar disappears once you are done. In that case do not
    # forget to add the "end" parameter to print function.
    print(f'[{max_width * "#"}]')


if __name__ == '__main__':
    list_of_elements = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    for e in range_with_progress(list_of_elements):
        time.sleep(0.2)

Comments

0

If you are using Python 3 then this is for you and it really works.

print(value , sep='',end ='', file = sys.stdout , flush = False)

1 Comment

does it work even if the value is a pandas dataframe ?
0

Just figured this out on my own for showing a countdown but it would also work for a percentage.

import time
#Number of seconds to wait
i=15
#Until seconds has reached zero
while i > -1:
    #Ensure string overwrites the previous line by adding spaces at end
    print("\r{} seconds left.   ".format(i),end='')
        time.sleep(1)
        i-=1
    print("") #Adds newline after it's done

As long as whatever comes after '/r' is the same length or longer (including spaces) than the previous string, it will overwrite it on the same line. Just make sure you include the end='' otherwise it will print to a newline. Hope that helps!

Comments

0

for object "pega" that provides StartRunning(), StopRunning(), boolean getIsRunning() and integer getProgress100() returning value in range of 0 to 100, this provides text progress bar while running...

now = time.time()
timeout = now + 30.0
last_progress = -1

pega.StartRunning()

while now < timeout and pega.getIsRunning():
    time.sleep(0.5)
    now = time.time()

    progress = pega.getTubProgress100()
    if progress != last_progress:
        print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", end='', flush=True)
        last_progress = progress

pega.StopRunning()

progress = pega.getTubProgress100()
print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", flush=True)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.