输出到同一行覆盖先前的输出?


95

我正在写一个FTP下载器。代码的一部分是这样的:

ftp.retrbinary("RETR " + file_name, process)

我正在调用函数进程来处理回调:

def process(data):
    print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
    file.write(data)

输出是这样的:

1784  KB / KB 1829 downloaded!
1788  KB / KB 1829 downloaded!
etc...   

但我希望它打印此行,下次重新打印/刷新它,因此它只会显示一次,我会看到下载进度。

如何做呢?



Answers:


185

这是Python 3.x的代码:

print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!', end='\r')

end=关键字是什么做的工作在这里-在默认情况下,print()在一个换行符(结束\n)字符,但可以使用不同的字符串替换。在这种情况下,用回车符结束该行,而是将光标返回到当前行的开头。因此,无需sys为此类简单用法导入模块。print()实际上有许多关键字参数可以用来大大简化代码。

要在Python 2.6+上使用相同的代码,请将以下行放在文件顶部:

from __future__ import print_function

6
请注意,打印功能还可以在Python通过在文件的顶部添加以下导入使用2.6+: from __future__ import print_function
janin 2012年

12
在python <3.0中,语句末尾的逗号将阻止“ \ n”: print "foo",但是,在此之后您仍然需要刷新才能看到更改:sys.stdout.flush()
Tobias Domhan

30
我发现我需要\r在字符串的开头包含,然后进行设置end=''以使其正常工作。当我结束时,我认为我的终端不喜欢它\r
-Jezzamon

2
在所有当前的Python 3版本中,您都可以添加flush=Trueprint()函数中以确保刷新缓冲区(仅在\n写入换行符时才刷新标准行缓冲区)。
马丁·彼得斯

4
在Jupyter笔记本电脑中,\r一开始使用,end=''效果最佳,最流畅。如果该字符串也可以使用flush=True,但不平滑\r,则在末尾使用with 并end='\r'删除该行及其换行符。
Dave X

40

如果您只想更改一行,请使用\r\r表示回车。它的作用仅仅是将插入号放回当前行的开头。它不会删除任何内容。同样,\b可用于向后退一个字符。(某些终端可能不支持所有这些功能)

import sys

def process(data):
    size_str = os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!'
    sys.stdout.write('%s\r' % size_str)
    sys.stdout.flush()
    file.write(data)

1
我会补充说这\r意味着回车。它的作用仅仅是将插入号放回当前行的开头。它不会删除任何内容。同样,\b可用于向后退一个字符。(某些终端可能不支持所有这些功能)
Adrien Plisson

sys.stdout.write('%s\r', size_str')我认为您的意思是,sys.stdout.write('%s\r' % size_str)但它不起作用。
克里斯蒂安

@Adrien:很好,补充。@Kristian:谢谢,更新了,已经很晚了。
山姆·多兰

还要注意printsys.stdout.write如果愿意,您仍然可以使用代替:print size_str + "\r",可以。将,在打印语句结尾抑制换行; sys.stdout.flush()仍然需要
Jeff

19

看一下curses模块文档curses模块HOWTO

真正的基本例子:

import time
import curses

stdscr = curses.initscr()

stdscr.addstr(0, 0, "Hello")
stdscr.refresh()

time.sleep(1)

stdscr.addstr(0, 0, "World! (with curses)")
stdscr.refresh()

10
不幸的是,curses仅在Unix上可用。OP没有告诉我们他的应用程序针对的是哪个操作系统……
Adrien Plisson

我很习惯在Linux下工作,以至于我在模块文档中都没有注意到有关该模块仅适用于UNIX的警告。.感谢您指出@Adrien。
Andrea Spadaccini 2011年

3
@AdrienPlisson,我知道这个问题是几年前提出的,但是实际上您可以将Curses放到Windows上:lfd.uci.edu/~gohlke/pythonlibs/#curses
Cold Diamondz 2014年

当我将其粘贴到我的Python解释器中时,终端变为fubar。从口译员那里退出并没有帮助。WTF ?!
allyourcode '16

使用clrtoeol时候第二行是比第一更短。
Serge Stroobandt

9

这是我的小课程,可以重印文本块。它会正确清除先前的文本,因此您可以用较短的新文本覆盖旧文本而不会造成混乱。

import re, sys

class Reprinter:
    def __init__(self):
        self.text = ''

    def moveup(self, lines):
        for _ in range(lines):
            sys.stdout.write("\x1b[A")

    def reprint(self, text):
        # Clear previous text by overwritig non-spaces with spaces
        self.moveup(self.text.count("\n"))
        sys.stdout.write(re.sub(r"[^\s]", " ", self.text))

        # Print new text
        lines = min(self.text.count("\n"), text.count("\n"))
        self.moveup(lines)
        sys.stdout.write(text)
        self.text = text

reprinter = Reprinter()

reprinter.reprint("Foobar\nBazbar")
reprinter.reprint("Foo\nbar")

2
这在Windows将无法正常工作达10的Windows,因为Windows 10是第一个窗口,以支持那些控制字符en.wikipedia.org/wiki/ANSI_escape_code
user136036

8

我发现对于python 2.7中的一个简单的print语句,只需将逗号放在your的末尾'\r'

print os.path.getsize(file_name)/1024, 'KB / ', size, 'KB downloaded!\r',

这比其他非python 3解决方案要短,但也更难以维护。


1
Python 2.7.10,它不打印任何内容。也许您可以在线进行编译,然后向我们发送链接以查看其工作方式...?
Shougo Makishima

5

您只需在字符串末尾添加“ \ r”,然后在打印功能末尾添加逗号。例如:

print(os.path.getsize(file_name)/1024+'KB / '+size+' KB downloaded!\r'),

1
这是针对python 3吗?如果是这样,将默认end参数设置为什么,则\n打印(...)KB downloaded!\r\n。我错了吗?
SR

使用end = '\r',而不是修复了Python 3的问题
Abhimanyu Pallavi苏德赫

4

我正在使用spyder 3.3.1-Windows 7-python 3.6,尽管可能不需要刷新。基于此帖子-https: //github.com/spyder-ide/spyder/issues/3437

   #works in spyder ipython console - \r at start of string , end=""
import time
import sys
    for i in range(20):
        time.sleep(0.5)
        print(f"\rnumber{i}",end="")
        sys.stdout.flush()

1

要超越python中的前一行,您需要做的就是在打印函数中添加end ='\ r',请测试以下示例:

import time
for j in range(1,5):
   print('waiting : '+j, end='\r')
   time.sleep(1)
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.