动态打印一行


306

我想做几条给出标准输出的语句,但不要在语句之间看到换行符。

具体来说,假设我有:

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

结果是:

1
2
3
4
.
.
.

如何使它看起来像:

1 2 3 4 5 ...

更妙的是,是否可以打印单号最后一个号码,所以只有一个号码在屏幕上在同一时间?


Answers:


482

更改print item为:

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

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

  • print(item, sep=' ', end='', flush=True) 在Python 3中

http://docs.python.org/reference/simple_stmts.html#print中:> '\n'除非print声明以逗号结尾,否则将在末尾写一个字符。如果语句仅包含关键字,则这是唯一的操作print
ewall

5
仅供参考:print(item,end =“”)可以在Python2.7中使用,方法是在文件顶部添加“ from future import print_function”。
Hec

2
但不幸的flush是无法正常工作from __future__ import print_function
Timmmm

@ewall如果我要这样做print(item, end=", "),那么还会添加,到最后一项中,如何防止将其添加,到最后一项中
MarcoBianchi

@SamirTendulkar如果您像原始问题一样使用for循环,则可以特例处理列表中的最后一项...
ewall

156

顺便说一句……如何每次都刷新它以便它在一个地方打印mi只需更改数字。

通常,这样做的方法是使用终端控制代码。这是一个非常简单的情况,对于该情况,您只需要一个特殊字符:用'\r'Python(和许多其他语言)编写的U + 000D CARRIAGE RETURN 。这是一个基于您的代码的完整示例:

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去的字符串,这样的开始,程序运行时,光标会一直在数字后。这不只是装饰性的:如果您反过来做的话,某些终端仿真器会非常混乱。
  • 如果您不包括最后一行,则在程序终止后,您的外壳程序将在数字的顶部显示其提示。
  • stdout.flush在某些系统上,这是必需的,否则您将不会获得任何输出。其他系统可能不需要它,但是它没有任何危害。

如果您发现这不起作用,那么您首先应该怀疑的是您的终端仿真器有问题。该vttest程序可以帮助你测试。

你可以更换stdout.write一个print声明,但我宁愿不要混淆print与直接使用的文件对象。


什么是flush()函数?因为没有它,它对我有用!
波尔

1
通常,Python的文件对象会累积数据,因此它们可以将其大块发送到操作系统。通常,这是您要访问磁盘上的文件的目的,但是它会干扰此类任务。 flush()强制文件立即将所有内容发送到操作系统。令我惊讶的是,没有它,它对您有用-在我添加它之前,它对我不起作用。
zwol

1
@ user1995839有一些隐藏光标的控制代码,但是如果要这样做,我强烈建议您使用ncurses它来完成。
zwol 2014年

1
sys.stdout.flush()似乎对我Freebsd具有强制性Python 2.7
Hakim

1
请注意,回车不能在Python REPL中正常工作(至少对我而言,在Ubuntu上);您需要执行脚本,而不仅仅是运行REPL命令,才能使其中任何一个起作用。
Mark Amery

50

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

实际上,在我看来,您的解决方案每次都会打印相同数量的退格键。因此,如果to为20,它将在打印数字1..9时打印额外的退格键。您是否不应该在循环内计算数字并将其基于i的值?
亚当·克罗斯兰

它会右对齐数字并始终删除所有内容。我还没有测试过这样做或在每次迭代中计算要删除多少位数的速度是否更快。
蒂姆·皮茨克

或者,将其基于i的前一个值来考虑数字位数的变化。
亚当·克罗斯兰

啊,是的,我忽略了正确的理由。好的解决方案。
亚当·克罗斯兰

听起来相当复杂。如果一年以后我必须看一下代码,我可能不明白自己在那做的事情。(只是不得不读的程序我在2007年写的-我这么高兴,我写在Python)
蒂姆Pietzcker

16

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

我只是使用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   

在这里查看更多


14

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

print item,

另外,如果您使用的是Python 2.6或更高版本,则可以使用新的打印功能,该功能可以让您指定在要打印的每个项目的末尾甚至都不应该有空格(或者允许您指定要结束的任何位置)想):

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

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

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

13

更改

print item

print "\033[K", item, "\r",
sys.stdout.flush()
  • “ \ 033 [K”清除到行尾
  • \ r,返回到行的开头
  • flush语句确保它立即显示,以便您获得实时输出。

这对于Python 2.7非常有用。您能否提供参考,以了解有关\033[K代码的知识?我想了解更多有关它们的信息。
Klik

print已经在内部刷新。无需调用。print不同于sys.stdout.write()您必须冲洗到屏幕上的位置
加布里埃尔博览会

5

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

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

4
一种解读会读更好,也许会更快:print ' '.join(str(x) for x in range(1, 10))
Mu Mind

我第二次使用列表理解。在这种情况下,它甚至更易于阅读。
奥斯汀·亨利

5

我在2.7上使用的另一个答案是仅打印“。”。每次循环运行(向用户表明事情还在运行)是这样的:

print "\b.",

打印“。” 每个字符之间没有空格。看起来更好一点,并且效果很好。\ b是那些想知道的退格字符。


4

这么多复杂的答案。如果您拥有python 3,只需将其放在\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依此类推。


谢谢,这正是我所需要的print('\r' + filename + " ", end = '', flush=True)
McPeppr

3

要使数字彼此覆盖,可以执行以下操作:

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

只要在第一列中打印该数字,它就应该起作用。

编辑:这是一个即使没有在第一栏中打印也可以使用的版本。

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

我应该注意,此代码已经过测试,并且可以在Windows的Windows 2.5的WIndows控制台中正常运行。根据另一些说法,可能需要刷新stdout才能看到结果。YMMV。


3

“顺便说一下……如何每次都刷新它,以便它在一个地方打印mi只需更改数字即可。”

这确实是一个棘手的话题。什么扎克建议(输出控制台控制代码)是实现这一目标的方法之一。

您可以使用(n)个curses,但这主要适用于* nixes。

在Windows上(这是有趣的部分),它很少被提及(我不明白为什么),您可以将Python绑定到WinAPI(默认情况下还与ActivePython一起使用http://sourceforge.net/projects/pywin32/)-它不是努力工作,效果很好。这是一个小例子:

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代码引起的-pythonic绑定是更容易使用。

当然,所有其他答案都是不错的,而且是Python语言的,但是...如果我想在一行中打印怎么办?还是写多行文本,而不是清除并重新写相同的行?我的解决方案使这成为可能。



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.

0

如果只想打印数字,则可以避免循环。

# 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花费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花费491.466823551ms


使用列表理解而不是应当更快map
cji

是的,很好的例子。我喜欢它,但我需要显示解析结果。首先,我计算数据库中的项目,而不是打印剩余的项目。
波尔

0

最好的方法是使用 \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

0

在Python 3中,您可以这样操作:

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

输出:

1 2 3 4 5 6 7 8 9 

元组:您可以对元组执行相同的操作:

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

我已经在这里尝试了所有示例,但在python 3.8中均无效,请获取更多答案。
KOTZ

我已经使用python 3.7进行了测试
Stryker

我的意思是,这些选项都不能覆盖问题末尾所建议的最后一个数字。
KOTZ

0

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

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

但这不会覆盖。


0

对于那些像我一样挣扎的人,我想出了以下似乎在python 3.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)

0
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,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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.