特定场景下回车符(\r)无法实现行覆盖问题排查
问题:Python中使用\r无法实现行覆盖的原因
已知用\r回车符可以让输出覆盖前一行,如下代码能正常运行:
import time for x in range(10): print(x, end='\r') time.sleep(0.1)
但以下包含生成器的代码却无法实现行覆盖:
import time def ft_progress(list): to_print = range(0, len(list), min(int(len(list) / 30) + 1, 30)) for i2 in list: i = abs(i2) print("[", str("%.2f" % (100 * (i + 1) / len(list))).rjust(6), "% ]", end='\r') yield i ret = 0 X = range(100) # 示例X for elem in ft_progress(X): ret += (elem + 3) % 5 time.sleep(0.01) print() print(ret)
需要生成器返回值同时打印进度,但输出无法被覆盖,尝试在print开头加\r也无效,求原因。
原因分析
问题出在主循环里的print()和print(ret)操作:
print()默认会在输出末尾添加\n换行符,执行后光标会跳到新的一行。- 后续的
print(ret)又会输出一行内容,此时进度条所在的行已经成为历史行,后续用\r只能覆盖当前光标所在行,无法再回到之前的进度条行进行覆盖。 - 生成器里的
print(..., end='\r')确实能覆盖它所在的行,但主循环里的两次print不断产生新行,导致进度条和ret的输出分散在不同行,完全失去了覆盖效果。
解决办法
把进度条和ret的输出整合到同一行,用\r覆盖整个行内容,避免产生新行:
修改后的代码示例:
import time def ft_progress(list): total = len(list) for idx, i2 in enumerate(list): i = abs(i2) progress = 100 * (idx + 1) / total yield i, progress ret = 0 X = range(100) for elem, progress in ft_progress(X): ret += (elem + 3) % 5 time.sleep(0.01) # 统一打印进度和ret,用\r回到行首覆盖之前内容 print(f"[ {progress:6.2f} % ] ret: {ret}", end='\r') # 循环结束后打印换行,避免最后一行被后续输出覆盖 print()
这样所有输出都集中在同一行,每次循环用\r回到行首覆盖全部内容,就能实现预期的行覆盖效果。
内容的提问来源于stack exchange,提问作者kubo
相关产品推荐
相关产品推荐

