Python 3 多行打印更新

7

是否可以打印和更新多行文本? 这适用于单行文本:

print ("Orders: " + str(OrderCount) + " Operations: " + str(OperationCount), end="\r")

而且,注意:(当然数字会因为循环而更新)
Orders: 25 Operations: 300

我尝试过这个:

我已经尝试了这个:

print ("Orders: " + str(OrderCount) + "\rOperations: " + str(OperationCount), end="\r\r")

并且要注意,数字确实正确更新了。
Operations: 300

寻找两行类似于以下内容的更新:

Orders: 25
Operations: 300

而不是:

Orders: 23
Operations: 298

Orders: 24
Operations: 299

Orders: 25
Operations: 300
3个回答

23

\r 是回车符,光标将移动到行的开头(第0列)。从那里开始,写入更多文本将覆盖以前写过的内容,因此最终只保留了最后一行(长到足以覆盖之前所写的所有内容)。

你需要 \n,一个换行符,它使光标移到下一行(并再次从第0列开始):

print("Orders: " + str(OrderCount) + "\nOperations: " + str(OperationCount), end="\n\n")

不要使用 str()+ 进行字符串拼接,考虑使用带有str.format() 的字符串模板:

print("Orders: {}\nOperations: {}\n".format(OrderCount, OperationCount))

或者一个格式化字符串字面值:

print(f"Orders: {OrderCount}\nOperations: {OperationCount}\n")

如果您想使用 \r 来更新两行,可以使用ANSI控制码;打印 \x1B[2A (ESC [ 2 A) 将光标向上移动2次,根据需要进行调整。这是否起作用取决于您支持的平台

在我的Mac上,以下演示可行并且可以更新两行随机数字;我使用 ESC [ 0 K 确保行中剩余的任何字符都被擦除:

import random, time

orders = 0
operations = 0

UP = "\x1B[3A"
CLR = "\x1B[0K"
print("\n\n")  # set up blank lines so cursor moves work
while True:
   orders += random.randrange(1, 3)
   operations += random.randrange(2, 10)

   print(f"{UP}Orders: {orders}{CLR}\nOperations: {operations}{CLR}\n")

   time.sleep(random.uniform(0.5, 2))

演示:

动画GIF演示了2行文本多次更新

你也可以使用Curses切换到完全的终端控制,或者将所有内容放在一行上。如果您要选择Curses方法,请注意,Windows兼容性最好是不可靠的。


这两种解决方案都不会更新控制台: 我得到的结果是: 订单数:88 操作数:197 订单数:88 操作数:198当然还有很多行。 - Mattman85208
@MatthewCox:从您的评论源代码中看到了换行符。那么您并不清楚,请更新您的问题以解释您期望的输出。 - Martijn Pieters
如果我想添加第三行并更新其值,该如何更改代码以使其正常工作? - Paras Gupta
1
@ParasGupta:试着仔细想一下;如果你必须使用光标键手动完成此操作,你需要向上移动4次,而不是3次。因此,请调整“UP”ANSI代码,将“3”替换为“4”。或者,正如我的答案所述:根据需要调整数字 - Martijn Pieters
我尝试了你的代码,但是在我的终端上仍然看到了新行,你可能需要改成这样: print(f"{UP}订单:{orders}{CLR}操作:{operations}{CLR}", end="\r") - DagicCross
显示剩余2条评论

1
这更像是一个“升级”而不是一个“答案”。使用“Martijn Pieters”的答案,我创建了一个函数,它不仅可以在两行中进行换行,还可以根据需要在任何位置进行换行(示例1)。你也可以进行普通的打印,这样打印的内容将保留在屏幕上,对于显示错误或调试非常有用(示例2)。我在Windows 11上使用PowerShell终端。
    last_nrows = None # Global variable
    def print_csi( msgs:list ):
        global last_nrows
        
        csi_up = f"\x1B[{last_nrows}A"
        csi_clr= "\x1B[0K"
        
        if last_nrows is None: # only executed one time when last_nrows is resetted (None)
            print('\n'*(len(msgs)-1))
            csi_up = f"\x1B[{len(msgs)}A"
        else: # clear the prompt if new msgs have less rows than the previous msgs, else overwrite
            if last_nrows > len(msgs):
                print(f'{csi_up}{csi_clr}')
                for r in range( 1, last_nrows ): print(f'{csi_clr}')
        
        last_nrows = len(msgs)
        print(f'{csi_up}{msgs[0]}{csi_clr}')
        for r in range( 1, len(msgs) ): print(f'{msgs[r]}{csi_clr}')

    print_csi( ['Line 1', 'Line 2'] ) # Call function - 'msgs' can not be empty

例子1 - 代码: 我随机选择要打印的行数,并在最后清除它。
    for i in range(10):
        # Create random list from 1 to 9 rows
        msgs = list()
        msg_nrows = random.randrange(1, 10)
        for rows in range(msg_nrows):
            msgs.append( f'NRows: {msg_nrows} - ' + f'{rows+1}'*9 ) 
        print_csi(msgs)
        time.sleep(0.2)
    time.sleep(2)
    print_csi(['']) # Clear rows  

示例1 - 演示: {{link1:演示第一个示例的动画GIF}}
示例2 - 代码: 与示例1相同,但我在中间进行了普通打印,并且它保持在屏幕上 - 要做到这一点,您需要将'last_nrows'重置为None。唯一的问题是每次重置'last_nrows'时都会创建一个空行。
    for j in range(5):
        last_nrows = None # Need to be resetted
        print('DO NOT REMOVE THIS LINE')
        for i in range(2):
            # Create random list from 1 to 9 rows
            msgs = list()
            msg_nrows = random.randrange(1, 10)
            for rows in range(msg_nrows):
                msgs.append( f'NRows: {msg_nrows} - ' + f'{rows+1}'*9 ) 
            print_csi(msgs)
            time.sleep(0.7)
        print_csi(['']) # Clear rows 

示例2 - 演示: {{link1:演示第二个示例的动画GIF}}

-2
你可能想要使用 \n 而不是 \r\r 是“回车符”,也称为“返回到行首” - 这样你就会在“订单”上覆盖“操作”。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接