在一行中动态打印

我想做几个语句,给出标准输出,而不看到换行之间的语句。

具体来说,假设我有:

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

结果是:

1
2
3
4
.
.
.

如何让它看起来像:

1 2 3 4 5 ...

更好的是,是否可以将单个数字打印为最后一个数字,以便一次只有一个数字出现在屏幕上?

685882 次浏览

使用print item,使打印语句省略换行符。

在Python 3中,它是print(item, end=" ")

如果你想让每个数字都显示在相同的位置,使用例如(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),

在Python 3中,这有点复杂;在这里,你需要刷新sys.stdout,否则在循环结束之前它不会打印任何东西:

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()

print item更改为:

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

如果你想动态打印数据,请使用以下语法:

  • print(item, sep=' ', end='', flush=True)在Python 3
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.

你可以在你的print语句中添加一个尾随逗号,在每次迭代中打印一个空格而不是换行符:

print item,

或者,如果你使用的是Python 2.6或更高版本,你可以使用新的print函数,它允许你指定甚至不应该在打印的每一项的结尾出现空格(或者允许你指定任何你想要的结尾):

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

最后,你可以通过从sys模块导入标准输出直接写入标准输出,它会返回一个类文件对象:

from sys import stdout
...
stdout.write( str(item) )

打印语句末尾的逗号省略了新行。

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

但这不会覆盖。

为了让数字相互覆盖,你可以这样做:

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

只要把数字打印在第一列,这就可以工作。

< p >编辑: 这里有一个版本,即使没有打印在第一列,也可以工作
prev_digits = -1
for i in range(0,1000):
print("%s%d" % ("\b"*(prev_digits + 1), i)),
prev_digits = len(str(i))

我应该指出,这段代码经过测试,在Windows上的Python 2.5中,在Windows控制台中工作得很好。根据其他一些方法,可能需要刷新stdout才能查看结果。YMMV。

顺便说一下......如何每次刷新它,所以它打印mi在一个地方,只是改变数字。

一般来说,这样做的方法是使用终端控制码。这是一个特别简单的情况,你只需要一个特殊的字符:U+000D CARRIAGE RETURN,它用Python(和许多其他语言)编写为'\r'。下面是一个基于你的代码的完整示例:

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

有些事情可能会令人惊讶:

  • \r位于字符串的开头,以便在程序运行时,光标始终位于该数字之后。这不仅仅是表面上的:如果你反过来做,一些终端模拟器会非常混乱。
  • 如果您不包括最后一行,那么在程序终止后,shell将在数字上方打印提示符。
  • stdout.flush在某些系统上是必要的,否则你不会得到任何输出。其他系统可能不需要它,但它不会造成任何损害。

如果你发现这不起作用,你应该怀疑的第一件事是你的终端模拟器有bug。vt程序可以帮助你测试它。

你可以用print语句替换stdout.write,但我不喜欢将print与直接使用文件对象混合使用。

“顺便说一下......如何刷新它,所以它打印mi在一个地方,只要改变数字。”

这真的是个棘手的话题。扎克所建议的(输出控制台控制代码)是实现这一点的一种方法。

你可以使用(n)诅咒,但这主要适用于*nix。

在Windows上(这里是有趣的部分),这很少被提及(我不明白为什么),你可以使用Python绑定到WinAPI (http://sourceforge.net/projects/pywin32/默认也带有ActivePython) -这并不难,而且工作得很好。这里有一个小例子:

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 )

或者,如果你想使用print(语句或函数,没有区别):

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模块可以让你用windows控制台做更多有趣的事情…我不是WinAPI的忠实粉丝,但最近我意识到我对它的反感至少有一半是由用C语言编写WinAPI代码引起的——python绑定更容易使用。

当然,所有其他的答案都很棒,而且很深奥,但是……如果我想打印以前的行怎么办?或者写多行文本,而不是清除它,再写相同的行?我的解决方案使之成为可能。

如果你只是想打印数字,你可以避免循环:

# 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

和其他例子一样,
我使用类似的方法,但不是花费时间计算最后的输出长度,等等,

我简单地使用ANSI代码转义移回行开始,然后在打印当前状态输出之前清除整行。

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()

为了在你的迭代循环中使用,你只需要调用如下代码:

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

在这里看到更多

我认为一个简单的连接应该工作:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)

实现这一点的最佳方法是使用 \r字符

试试下面的代码:

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

改变

print item

print "\033[K", item, "\r",
sys.stdout.flush()
  • 033[ K ]清除到行的末尾
  • R 返回到行首
  • Flash 语句确保它立即显示,这样您就可以得到实时输出。

用于 Python 2.7

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

巨蟒3

for x in range(0, 3):
print(x, end=" ")

我在2.7中使用的另一个答案,我只是打印一个“每次循环运行时(向用户指示事情仍在运行)是这样的:

print "\b.",

它打印的“字符之间没有空格。看起来好一点,效果也不错。对于那些想知道答案的人来说,b 是一个退格字符。

在 Python 3中,你可以这样做:

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

产出:

1 2 3 4 5 6 7 8 9

Tuple: 你可以对 Tuple 做同样的事情:

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


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

输出:

1 - 2 - 3 - 4 - 5 -

另一个例子:

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

产出:

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

你甚至可以像这样解压元组:

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)

产出:

1 2
A B
3 4
Cat Dog

另一种变化是:

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

产出:

1
2




A
B




3
4




Cat
Dog

这么多复杂的答案。如果你有 python3,只要把 \r放在打印的开头,然后加上 end='', flush=True:

import time


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

这将写入 0 foo bar,然后 1 foo bar等,在地方。

对于那些像我一样挣扎的人,我想出了下面这个在 python3.7.4和3.5.2中都可以使用的方法。

我将范围从100扩展到1,000,000,因为它运行非常快,您可能看不到输出。这是因为设置 end='\r'的一个副作用是最后的循环迭代会清除所有的输出。需要更长的数字来证明它是有效的。 这个结果可能不是在所有情况下都令人满意,但是在我的情况下是很好的,OP 没有指定这样或那样的方式。您可以使用一个 if 语句来计算正在迭代的数组的长度,等等来规避这个问题。 在我的例子中,让它工作的关键是将方括号 "{}".format()结合起来。否则就没用了。

下面应该按原样工作:

#!/usr/bin/env python3


for item in range(1,1000000):
print("{}".format(item), end='\r', flush=True)
for item in range(1,100):
if item==99:
print(item,end='')
else:
print (item,end=',')

产出: 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,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,44,45,46,47,48,49,50,51,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,88,89,90,91,92,93,94,96,97,98,99

或者更简单:

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

end="\r"将覆盖第一次打印的开头[0: ]。

如果希望它作为字符串,可以使用

number_string = ""
for i in range(1, 100):
number_string += str(i)
print(number_string)

注意: 我指出了这个解决方案,因为如果下一张印刷品的长度比上一张小,我看到的其他大多数解决方案都不起作用。

如果您知道要删除的内容,并且能够负担得起全局变量,那么只需用空格覆盖最后一行即可。

  1. 在打印之前,将字符串的长度存储为“ n”。
  2. 打印它,但以‘ r’结尾(它返回到行的开头)。
  3. 下次,在打印您的邮件之前,在行上打印 n’空格。
_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)

例子:

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