Print in one line dynamically [duplicate]
Asked Answered
T

22

369

I would like to make several statements that give standard output without seeing newlines in between statements.

Specifically, suppose I have:

for item in range(1,100):
    print item

The result is:

1
2
3
4
.
.
.

How get this to instead look like:

1 2 3 4 5 ...

Even better, is it possible to print the single number over the last number, so only one number is on the screen at a time?

Turcotte answered 14/7, 2010 at 19:3 Comment(1)
Related post - How to print without newline or space?Flame
C
555

Change print item to:

  • print item, in Python 2.7
  • print(item, end=" ") in Python 3

If you want to print the data dynamically use following syntax:

  • print(item, sep=' ', end='', flush=True) in Python 3
Cirro answered 14/7, 2010 at 19:5 Comment(3)
From http://docs.python.org/reference/simple_stmts.html#print: > A '\n' character is written at the end, unless the print statement ends with a comma. This is the only action if the statement contains just the keyword print.Cirro
FYI: print(item, end=" ") can be used in Python2.7 by adding 'from future import print_function' at top of file.Zacarias
But flush does not work with from __future__ import print_function unfortunately.Ampoule
E
172

By the way...... How to refresh it every time so it print mi in one place just change the number.

In general, the way to do that is with terminal control codes. This is a particularly simple case, for which you only need one special character: U+000D CARRIAGE RETURN, which is written '\r' in Python (and many other languages). Here's a complete example based on your code:

from sys import stdout
from time import sleep
for i in range(1,20):
    stdout.write("\r%d" % i)
    stdout.flush()
    sleep(1)
stdout.write("\n") # move the cursor to the next line

Some things about this that may be surprising:

  • The \r goes at the beginning of the string so that, while the program is running, the cursor will always be after the number. This isn't just cosmetic: some terminal emulators get very confused if you do it the other way around.
  • If you don't include the last line, then after the program terminates, your shell will print its prompt on top of the number.
  • The stdout.flush is necessary on some systems, or you won't get any output. Other systems may not require it, but it doesn't do any harm.

If you find that this doesn't work, the first thing you should suspect is that your terminal emulator is buggy. The vttest program can help you test it.

You could replace the stdout.write with a print statement but I prefer not to mix print with direct use of file objects.

Exhaust answered 14/7, 2010 at 19:22 Comment(11)
What meen flush() function? Becouse it work for me without that function!Turcotte
Normally, Python's file objects accumulate data so they can send it to the operating system in big chunks. This is what you want for access to files on disk, usually, but it interferes with this kind of task. flush() forces a file to send whatever it's got to the operating system right now. I'm surprised it works for you without that -- it didn't work for me until I added it.Exhaust
I got win32 OS, and python 2.6. What kind of OS do you have?Turcotte
Linux and python 2.6. It could very easily be a difference between Windows' "console windows" and Unix pseudoterminals. Don't worry about it for now.Exhaust
I'm using this method but the cursor in my terminal is running from the start to the end of my output every time I print out.. Is there any way to stop this behavior? It's hard to watch :/Ilanailangilang
@Ilanailangilang There are control codes to hide the cursor, but if you're going to do that I strongly recommend you use ncurses to do it.Exhaust
sys.stdout.flush() seems to be mendatory on my Freebsd with Python 2.7Mole
When I use print with Python3.4 on a Linux (Ubuntu 14) it doesn't work.Peasecod
This was a much more useful answer (for me) because it works with both Python versions and was the only thing that worked on my linux Mint system.Hoick
Note that carriage return doesn't work properly within the Python REPL (at least for me, on Ubuntu); you need to be executing a script, not just running a REPL command, for any of this to work.Rinee
@MarkAmery Right, that's because the REPL messes with the terminal itself in order to provide command history and editing. A fancier REPL might even let you manipulate that process; CPython's doesn't; I don't know if IPython does.Exhaust
T
56

Use print item, to make the print statement omit the newline.

In Python 3, it's print(item, end=" ").

If you want every number to display in the same place, use for example (Python 2.7):

to = 20
digits = len(str(to - 1))
delete = "\b" * (digits + 1)
for i in range(to):
    print "{0}{1:{2}}".format(delete, i, digits),

In Python 3, it's a bit more complicated; here you need to flush sys.stdout or it won't print anything until after the loop has finished:

import sys
to = 20
digits = len(str(to - 1))
delete = "\b" * (digits)
for i in range(to):
   print("{0}{1:{2}}".format(delete, i, digits), end="")
   sys.stdout.flush()
Took answered 14/7, 2010 at 19:5 Comment(9)
Actually, it looks to me like your solution will print the same number of backspaces every time. So, if to is 20, it will print an extra backspace while printing digits 1..9. Shouldn't you calculate digits inside the loop and base it off of the value of i?Blackford
It right-justifies the number and always deletes everything. I haven't tested if it's faster to do that or to calculate in each iteration how many digits there are to be erased just now.Took
Or, base it off of the previous value of i to account for when the number of digits changes.Blackford
Sounds fairly complicated. I probably wouldn't understand what I had done there if I had to look at my code a year from now. (Just had to read a program I wrote in 2007 - I'm so glad I wrote it in Python.)Took
I know it's more or less platform independent, but I can't say I like it. Having len( s ) and printing 2 * len( s ) characters... And what if there's newline somewhere? ( Yes, I'm shamelessly advertising my answer below ;) )Tarryn
@TimPietzcker The solution for python3 does not work for me. Has this behavior changed?Mcintyre
@TimPietzcker output does not write to the same line for me, it still prints each statement on a new line. With or without the \b makes no differenceMcintyre
Where exactly are you printing to? I'm using the Python command line shell on Windows x64.Took
I'm printing to stdout in linux from within a script.Mcintyre
J
22

Like the other examples,
I use a similar approach but instead of spending time calculating out the last output length, etc,

I simply use ANSI code escapes to move back to the beginning of the line and then clear that entire line before printing my current status output.

import sys

class Printer():
    """Print things to stdout on one line dynamically"""
    def __init__(self,data):
        sys.stdout.write("\r\x1b[K"+data.__str__())
        sys.stdout.flush()

To use in your iteration loop you would just call something like:

x = 1
for f in fileList:
    ProcessFile(f)
    output = "File number %d completed." % x
    Printer(output)
    x += 1   

See more here

Jamie answered 15/6, 2011 at 16:27 Comment(0)
G
15

You can add a trailing comma to your print statement to print a space instead of a newline in each iteration:

print item,

Alternatively, if you're using Python 2.6 or later, you can use the new print function, which would allow you to specify that not even a space should come at the end of each item being printed (or allow you to specify whatever end you want):

from __future__ import print_function
...
print(item, end="")

Finally, you can write directly to standard output by importing it from the sys module, which returns a file-like object:

from sys import stdout
...
stdout.write( str(item) )
Gripsack answered 14/7, 2010 at 19:8 Comment(0)
F
15

change

print item

to

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\033[K" clears to the end of the line
  • the \r, returns to the beginning of the line
  • the flush statement makes sure it shows up immediately so you get real-time output.
Finedraw answered 14/7, 2015 at 21:37 Comment(2)
This is great for Python 2.7. Can you provide a reference to where you learned about the \033[K code? I'd like to learn more about them.Bette
print already flushes internally. No need to call it. print is different from sys.stdout.write() where you do have to flush to screenGrilse
A
15

So many complicated answers. If you have python 3, simply put \r at the start of the print, and add end='', flush=True to it:

import time

for i in range(10):
    print(f'\r{i} foo bar', end='', flush=True)
    time.sleep(0.5)

This will write 0 foo bar, then 1 foo bar etc, in-place.

Appropriate answered 7/8, 2019 at 13:53 Comment(0)
C
5

Another answer that I'm using on 2.7 where I'm just printing out a "." every time a loop runs (to indicate to the user that things are still running) is this:

print "\b.",

It prints the "." characters without spaces between each. It looks a little better and works pretty well. The \b is a backspace character for those wondering.

Chlo answered 14/1, 2016 at 19:42 Comment(0)
A
4

I think a simple join should work:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)
Arjan answered 20/9, 2012 at 17:54 Comment(2)
A comprehension would read better and probably be faster: print ' '.join(str(x) for x in range(1, 10)).Intellectuality
I second the use of a list comprehension. In this case it would make it easier to read even.Plasticine
B
3

To make the numbers overwrite each other, you can do something like this:

for i in range(1,100):
    print "\r",i,

That should work as long as the number is printed in the first column.

EDIT: Here's a version that will work even if it isn't printed in the first column.

prev_digits = -1
for i in range(0,1000):
    print("%s%d" % ("\b"*(prev_digits + 1), i)),
    prev_digits = len(str(i))

I should note that this code was tested and works just fine in Python 2.5 on Windows, in the WIndows console. According to some others, flushing of stdout may be required to see the results. YMMV.

Blackford answered 14/7, 2010 at 19:15 Comment(0)
T
3

"By the way...... How to refresh it every time so it print mi in one place just change the number."

It's really tricky topic. What zack suggested ( outputting console control codes ) is one way to achieve that.

You can use (n)curses, but that works mainly on *nixes.

On Windows (and here goes interesting part) which is rarely mentioned (I can't understand why) you can use Python bindings to WinAPI (http://sourceforge.net/projects/pywin32/ also with ActivePython by default) - it's not that hard and works well. Here's a small example:

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    output_handle.WriteConsoleOutputCharacter( i, pos )
    time.sleep( 1 )

Or, if you want to use print (statement or function, no difference):

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    print i
    output_handle.SetConsoleCursorPosition( pos )
    time.sleep( 1 )

win32console module enables you to do many more interesting things with windows console... I'm not a big fan of WinAPI, but recently I realized that at least half of my antipathy towards it was caused by writing WinAPI code in C - pythonic bindings are much easier to use.

All other answers are great and pythonic, of course, but... What if I wanted to print on previous line? Or write multiline text, than clear it and write the same lines again? My solution makes that possible.

Tarryn answered 14/7, 2010 at 20:14 Comment(0)
C
2

for Python 2.7

for x in range(0, 3):
    print x,

for Python 3

for x in range(0, 3):
    print(x, end=" ")
Clinometer answered 17/12, 2015 at 13:3 Comment(0)
R
2

In Python 3 you can do it this way:

for item in range(1,10):
    print(item, end =" ")

Outputs:

1 2 3 4 5 6 7 8 9 

Tuple: You can do the same thing with a tuple:

tup = (1,2,3,4,5)

for n in tup:
    print(n, end = " - ")

Outputs:

1 - 2 - 3 - 4 - 5 - 

Another example:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for item in list_of_tuples:
    print(item)

Outputs:

(1, 2)
('A', 'B')
(3, 4)
('Cat', 'Dog')

You can even unpack your tuple like this:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]

# Tuple unpacking so that you can deal with elements inside of the tuple individually
for (item1, item2) in list_of_tuples:
    print(item1, item2)   

Outputs:

1 2
A B
3 4
Cat Dog

another variation:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for (item1, item2) in list_of_tuples:
    print(item1)
    print(item2)
    print('\n')

Outputs:

1
2


A
B


3
4


Cat
Dog
Rossen answered 13/4, 2018 at 16:28 Comment(3)
I have tried all the examples here and none work in python 3.8 Please get more answers.Family
I have tested it with python 3.7Rossen
What I mean is none of these options overwrite the last number like it was suggested at the end of the question.Family
E
2

For those struggling as I did, I came up with the following that appears to work in both python 3.7.4 and 3.5.2.

I expanded the range from 100 to 1,000,000 because it runs very fast and you may not see the output. This is because one side effect of setting end='\r' is that the final loop iteration clears all of the output. A longer number was needed to demonstrate that it works. This result may not be desirable in all cases, but was fine in mine, and OP didn't specify one way or another. You could potentially circumvent this with an if statement that evaluates the length of the array being iterated over, etc. The key to get it working in my case was to couple the brackets "{}" with .format(). Otherwise, it didn't work.

Below should work as-is:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)
Encephalogram answered 29/1, 2020 at 11:14 Comment(0)
F
2

Or even simpler:

import time
a = 0
while True:
    print (a, end="\r")
    a += 1
    time.sleep(0.1)

end="\r" will overwrite from the beginning [0:] of the first print.

Fletcherfletcherism answered 29/5, 2020 at 23:48 Comment(1)
It does display a number but on Mac OS 11 in the terminal using Bash I see the insertion point square over the first digit. This makes it hard to read.Brendanbrenden
L
2

Note: I point out this solution, because most of the others I've seen don't work if the length of the next print is smaller than the previous one.

If you know what you want to delete, and can afford a global variable, you can simply overwrite the last line with blank spaces.

  1. Before printing, store the length of your string as ‘n’.
  2. Print it, but end with ‘\r’ (it returns to the beginning of the line).
  3. Next time, before printing you message, print ’n’ blank spaces over the line.
_last_print_len = 0
def reprint(msg, finish=False):
    global _last_print_len
    
    # Ovewrites line with spaces.
    print(' '*_last_print_len, end='\r')
    
    if finish:
        end = '\n'
        # If we're finishing the line, we won't need to overwrite it in the next print.
        _last_print_len = 0
    else:
        end = '\r'
        # Store len for the next print.
        _last_print_len = len(msg)
    
    # Printing message.
    print(msg, end=end)

Examples:

for i in range(10):
    reprint('Loading.')
    time.sleep(1)
    reprint('Loading..')
    time.sleep(1)
    reprint('Loading...')
    time.sleep(1)

enter image description here

for i in range(10):
    reprint('Loading.')
    time.sleep(1)
    reprint('Loading..')
    time.sleep(1)
    reprint('Loading...', finish=True)
    time.sleep(1)

enter image description here

Lu answered 16/11, 2021 at 4:48 Comment(0)
V
1
In [9]: print?
Type:           builtin_function_or_method
Base Class:     <type 'builtin_function_or_method'>
String Form:    <built-in function print>
Namespace:      Python builtin
Docstring:
    print(value, ..., sep=' ', end='\n', file=sys.stdout)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep:  string inserted between values, default a space.
end:  string appended after the last value, default a newline.
Varicolored answered 14/7, 2010 at 19:6 Comment(0)
M
1

A comma at the end of the print statement omits the new line.

for i in xrange(1,100):
  print i,

but this does not overwrite.

Mortise answered 14/7, 2010 at 19:8 Comment(0)
B
0

If you just want to print the numbers, you can avoid the loop:

# python 3
import time

startnumber = 1
endnumber = 100

# solution A without a for loop
start_time = time.clock()
m = map(str, range(startnumber, endnumber + 1))
print(' '.join(m))
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('took {0}ms\n'.format(timetaken))

# solution B: with a for loop
start_time = time.clock()
for i in range(startnumber, endnumber + 1):
    print(i, end=' ')
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('\ntook {0}ms\n'.format(timetaken))
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
took 21.1986929975ms

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 
took 491.466823551ms
Brockwell answered 14/7, 2010 at 20:50 Comment(2)
Should be even faster with list comprehension instead of map.Tarryn
Yes good examples. I like it, but i need to show result of parsing. First I count the items i database than print how much remain.Turcotte
B
0

The best way to accomplish this is to use the \r character

Just try the below code:

import time
for n in range(500):
  print(n, end='\r')
  time.sleep(0.01)
print()  # start new line so most recently printed number stays
Boone answered 22/12, 2014 at 20:24 Comment(0)
B
0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Output: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99

Blindfold answered 12/5, 2020 at 15:43 Comment(0)
G
-1

If you want it as a string, you can use

number_string = ""
for i in range(1, 100):
  number_string += str(i)
print(number_string)
Gardiner answered 22/7, 2021 at 6:38 Comment(1)
This will not print dynamically as it iterates. You are collecting output into the string variable and printing in one statement. This is not what the question is asking. I'm going to downvote maybe.Turcotte

© 2022 - 2024 — McMap. All rights reserved.