可靠的Python输出套印

时间:2015-11-05 19:47:30

标签: python python-2.7 output ansi-escape

我有一些输出我想写一下,并且有一个简单的Python函数可以完成这个(在OS X上的终端)但我不确定我是否可以依赖它:

import sys
import time

def print_over(s):
    print(s, end='\r')
    print("\033[F" * (s.count('\n')+1))
    sys.stdout.flush() 
    time.sleep(0.2)

我知道会有一些情况,当然这不会起作用,但是很奇怪

  • 我可以期待它有多广泛地运作(例如,它只是OS X的一些怪癖,允许这样做),
  • 如何描述它的位置并且不会起作用(例如,是否有一些POSIX或其他标准可以保证它会发生),并且
  • 我是否可以从我的代码中检测到它是否会起作用。

2 个答案:

答案 0 :(得分:1)

忽略有关微软Console API(OP可以探索)的可移植性的讨论,并且只关注“ANSI-escapes”工作的地方:

这一行特别有意义,因为它是唯一使用的转义序列:

print("\033[F" * (s.count('\n')+1))

这对应于ECMA-48控件 CPL ,例如XTerm Control Sequences

CSI Ps F  Cursor Preceding Line Ps Times (default = 1) (CPL).
  • OP问“我有多广泛地期待它的运作”。这取决于。它在xterm中实现(而Terminal.app实现了相当大的一部分),但不是VT100或VT220的一部分(参见http://vt100.net的文档)。它被添加到1996的xterm中。所以考虑它仅限于模仿xterm的程序。

  • POSIX对此话题无话可说。 X/Open Curses(不属于POSIX)是关闭的 - 但CPL与任何terminfo功能都不对应。 ECMA-48是相关的,但无法保证ECMA-48中列出的任何功能在任何给定终端中实施。相反,它列举了可能性并规定了它们的语法。同样不能保证在另一个程序中找到xterm的任何给定功能(例如参见Comparing versions, by counting controls)。

  • 原则上,可以尝试使用光标位置报告( CPR 控制序列)来查看使用 CPL后光标的位置,但即使这对某些“xterm模拟器”来说也是不可靠的。

顺便说一句, CPL 控制序列接受一个repeat参数,因此可以重写print语句以使用它(而不是重复控制序列)。

如果您想要更轻松一点,使用 CUU (向上光标)控件可以与VT100配合使用,并且(如 CPL )可以使用重复计数进行参数化。那是"\033[A"

CSI Ps A  Cursor Up Ps Times (default = 1) (CUU).

答案 1 :(得分:0)

为什么不使用curses?它在Linux,OSX中原生运行,现在还有一个Windows implementation(报告为here)。

以下示例在大多数平台上都是可靠的:

from curses import wrapper
import time

def print_over(scr, s):
    scr.clear()
    scr.addstr(5, 0, s)
    scr.refresh()

def main(scr):
    for i in range(10, 110, 10):
        print_over(scr,'Progress: %d %%'%i)
        time.sleep(1)

wrapper(main)

修改

这是另一个不清除整个屏幕的例子:

from curses import tparm, tigetstr, setupterm
import time

def tput(cmd, *args):
    print (tparm(tigetstr(cmd), *args), end='') # Emulates Unix tput

class window():
    def __init__(s, x, y, w, h):
        s.x, s.y, s.w, s.h = x, y, w, h # store window coordinates and size

    def __enter__(s):
        tput('sc') # saves current cursor position
        s.clear()  # clears the window
        return s

    def __exit__(s, exc_type, exc_val, exc_tb):
        tput('rc') # restores cursor position

    def clear(s, fill=' '):
        for i in range(s.h):
            tput('cup', s.y+i, s.x) # moves cursor to the leftmost column
            print (fill*s.w, end='')

    def print_over(s, msg, x, y):
        tput('cup', s.y+y, s.x+x)
        print (msg, end='')

setupterm()
with window(x=5, y=10, w=80, h=5) as w:
    for i in range(10, 110, 10):
        w.clear()
        w.print_over('Progress: %d %%'%i, 5, 2)
        time.sleep(1)

在这里另一个覆盖最后一行:

from curses import tparm, tigetstr, setupterm
import time

def tput(cmd, *args):
    print (tparm(tigetstr(cmd), *args), end='') # Emulates Unix tput

setupterm()
for i in range(10, 110, 10):
    tput('el') # clear to end of line
    print (' Progress: %d %%'%i, end='\r')
    time.sleep(1)

基本上,原则是始终使用cursestput commands来避免任何显式转义字符。

请注意,您可能需要刷新标准输出或仅使用python -u启动脚本。