使用Python进行动态终端打印

58 投票
7 回答
108837 浏览
提问于 2025-04-15 18:22

有些应用程序,比如 hellanzb,可以在终端上显示数据,看起来就像是动态更新一样,类似于 top() 命令的效果。

在 Python 中,做这个的最佳方法是什么呢?我了解了一些关于日志记录和 curses 的内容,但不太确定该用哪个。我正在重新实现 top 命令。如果你有其他建议,我也很乐意听听。

7 个回答

8

通过使用print()命令将输出发送到终端时,可以使用“end”这个属性来避免滚动。

默认情况下,end='\n'表示换行。

如果你想要避免滚动并覆盖整行之前的内容,可以使用RETURN转义字符'\r'。

如果你只想重写最后四个字符,可以使用几个退格。

print(value, "_of_", total, end='\r')

注意 这个方法适用于标准系统终端。但在一些工具的终端模拟器中,比如IDLE,'\r'可能会出现问题,输出会和一些不可打印的字符连接在一起。

关于print()的额外信息 在上面的例子中,“of”两边的空格是为了确保我的值和“of”之间有空白。不过,print()的默认分隔符是一个空格,所以最终在值和“_of_”之间会有空白。

>> print (value, "_of_", total, end='\r')
8 _of_ 17

分隔符属性sep可以用来设置打印项目之间的字符。在我的例子中,我会把它改成一个空字符串(''),这样我的输出就符合我的需求了。

>> print (value, "_of_", total, sep='', end='\r')
8_of_17
21

正如大多数回答所说,在Linux上你几乎只能使用ncurses。但是,如果你不在Linux上,或者想要一些更高级的东西来创建终端界面呢?

我个人觉得在Python中缺少一个现代的、跨平台的终端API很让人失望,所以我写了asciimatics来解决这个问题。这个库不仅提供了一个简单的跨平台API,还提供了很多更高级的抽象功能,比如用户界面组件和动画,这些都可以轻松用来创建类似于top的界面。

80

如果你只需要更新一行内容,比如说制作一个进度条,最简单的方法就是使用 '\r'(回车符)和 sys.stdout

import sys
import time

for i in range(10):
    sys.stdout.write("\r{0}>".format("="*i))
    sys.stdout.flush()
    time.sleep(0.5)

如果你想要一个更完整的控制台界面,能够支持移动光标等功能,可以使用标准库中的 curses 模块:

import time
import curses

def pbar(window):
    for i in range(10):
        window.addstr(10, 10, "[" + ("=" * i) + ">" + (" " * (10 - i )) + "]")
        window.refresh()
        time.sleep(0.5)

curses.wrapper(pbar)

强烈建议使用 curses.wrapper 函数来调用你的主函数,这样可以在出错时自动清理终端,避免终端变得无法使用。

如果你要创建一个更复杂的界面,可以为屏幕的不同部分创建多个窗口,添加文本输入框和鼠标支持。

撰写回答