如何将先前的打印覆盖到标准输出?

2024-12-06 08:40:00
admin
原创
87
摘要:问题描述:如果我有以下代码:for x in range(10): print(x) 我会得到输出1 2 etc.. 我想要做的是,不是打印换行符,而是替换先前的值并用同一行上的新值覆盖它。解决方案 1:简易版一种方法是使用回车`''`符 ( ) 返回到行首而不前进到下一行。Python 3for ...

问题描述:

如果我有以下代码:

for x in range(10):
     print(x)

我会得到输出

1
2
etc..

我想要做的是,不是打印换行符,而是替换先前的值并用同一行上的新值覆盖它。


解决方案 1:

简易版

一种方法是使用回车`'
'`符 ( ) 返回到行首而不前进到下一行。

Python 3

for x in range(10):
    print(x, end='
')
print()

Python 2.7 向前兼容

from __future__ import print_function
for x in range(10):
    print(x, end='
')
print()

Python 2.7

for x in range(10):
    print '{}
'.format(x),
print

Python 2.0-2.6

for x in range(10):
    print '{0}
'.format(x),
print

在后两种情况下(仅限 Python 2),print 语句末尾的逗号指示不要转到下一行。最后一个 print 语句前进到下一行,因此提示不会覆盖最终输出。

管线清洁

如果您不能保证新行文本不短于现有行,那么您只需添加“清除到行尾”转义序列'x1b[1K''x1b'= ESC):

for x in range(75):
    print('*' * (75 - x), x, end='x1b[1K
')
print()

长线换行

所有这些方法都假设您输入的内容不超过行的长度。回车符只会返回到当前行的开头,因此如果您的输出超过一行,您只会删除最后一行。

如果这个问题严重到需要控制,您可以禁用换行功能,以防止光标换行到下一行。(相反,光标会停留在行尾,并且连续的字符会覆盖。)

使用 禁用换行print('x1b[7l', end=''),使用 重新启用换行print('x1b[7h', end='')请注意,任何时候都不会自动重新启用换行:如果程序因异常而终止,请不要让终端处于中断状态!

解决方案 2:

由于我是通过 Google 来到这里的,但我使用的是 Python 3,因此下面是它在 Python 3 中的工作方式:

for x in range(10):
    print("Progress {:2.1%}".format(x / 10), end="
")

相关答案在这里:如何在打印语句后抑制换行符?

解决方案 3:

@Mike DeSimone 的答案可能在大多数情况下都有效。但是...

for x in ['abc', 1]:
    print '{}
'.format(x),

-> 1bc

这是因为`'
'`仅仅返回到行首但不会清除输出。

如果 POSIX 支持对您来说足够了,以下命令将清除当前行并将光标保留在其开头:

print 'x1b[2K
',

它使用 ANSI 转义码来清除终端行。更多信息可以在 wikipedia和这篇精彩演讲中找到。

其他方法

我发现的另一个(可能更糟糕的)解决方案如下所示:

last_x = ''
for x in ['abc', 1]:
    print ' ' * len(str(last_x)) + '
',
    print '{}
'.format(x),
    last_x = x

-> 1

一个优点是它也可以在 Windows 上运行。

解决方案 4:

在访问此主题之前,我也有同样的问题。对我来说,sys.stdout.write 只有在我正确刷新缓冲区时才有效,即

for x in range(10):
    sys.stdout.write('
'+str(x))
    sys.stdout.flush()

如果不刷新,结果只会打印在脚本的末尾

解决方案 5:

抑制换行符并打印`
`。

print 1,
print '
2'

或者写入标准输出:

sys.stdout.write('1')
sys.stdout.write('
2')

解决方案 6:

这是 @Nagasaki45 答案的一个更简洁、更“即插即用”的版本。与此处的许多其他答案不同,它可以正确处理不同长度的字符串。它通过清除行来实现这一点,清除的空格数与打印的最后一行的长度相同。也适用于 Windows。

def print_statusline(msg: str):
    last_msg_length = len(getattr(print_statusline, 'last_msg', ''))
    print(' ' * last_msg_length, end='
')
    print(msg, end='
')
    sys.stdout.flush()  # Some say they needed this, I didn't.
    setattr(print_statusline, 'last_msg', msg)

用法

只需像这样使用即可:

for msg in ["Initializing...", "Initialization successful!"]:
    print_statusline(msg)
    time.sleep(1)

这个小测试表明,即使长度不同,线条也能被正确清除:

for i in range(9, 0, -1):
    print_statusline("{}".format(i) * i)
    time.sleep(0.5)

解决方案 7:

for x in range(10):
    time.sleep(0.5) # shows how its working
    print("
 {}".format(x), end="")

time.sleep(0.5) 用于显示如何删除先前的输出,并且当在打印消息的开头时如何打印新的输出“\r”,它将在新输出之前删除先前的输出。

解决方案 8:

尝试一下:

import time
while True:
    print("Hi ", end="
")
    time.sleep(1)
    print("Bob", end="
")
    time.sleep(1)

它对我有用。该 `end="
"`部分使它覆盖前一行。

警告!

如果您打印出,然后使用hi打印出,您将得到因为输出覆盖了前两个字母。如果您打印出带有空格(此处未显示)的 ,则它将输出。要解决此问题,请使用 打印出空格。hello`
hillohihi
`

解决方案 9:

这适用于 Windows 和 Python 3.6

import time
for x in range(10):
    time.sleep(0.5)
    print(str(x)+'
',end='')

解决方案 10:

我无法让此页面上的任何解决方案适用于IPython,但对@Mike-Desimone 的解决方案稍加改动就可以完成工作:不是以回车符终止行,而是以回车符开始行:

for x in range(10):
    print '
{0}'.format(x),

此外,这种方法不需要第二个打印语句。

解决方案 11:

接受的答案并不完美。首先打印的行将保留在那里,如果第二次打印未覆盖整个新行,则最终将得到垃圾文本。

为了说明问题,请将此代码保存为脚本并运行它(或者只是看一下):

import time

n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="
")
        time.sleep(0.01)
    print("Progress {:2.1%}".format(i / 100))

输出将会像这样:

Progress 0.0%%
Progress 1.0%%
Progress 2.0%%
Progress 3.0%%

对我来说,有效的方法是在留下永久印记之前清除线条。请随意调整以适应您的具体问题:

import time

ERASE_LINE = 'x1b[2K' # erase line command
n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="
")
        time.sleep(0.01)
    print(ERASE_LINE + "Progress {:2.1%}".format(i / 100)) # clear the line first

现在它可以按预期打印:

Progress 0.0%
Progress 1.0%
Progress 2.0%
Progress 3.0%

解决方案 12:

我有点惊讶没有人使用退格键。下面是一个使用它的程序。

import sys
import time

secs = 1000

while True:
    time.sleep(1)  #wait for a full second to pass before assigning a second
    secs += 1  #acknowledge a second has passed

    sys.stdout.write(str(secs))

    for i in range(len(str(secs))):
        sys.stdout.write('')

解决方案 13:

这是我的解决方案!Windows 10,Python 3.7.1

我不确定这段代码为什么有效,但它完全抹去了原始行。我根据前面的答案编译了它。其他答案只会将行返回到开头,但如果后面有一条较短的行,它看起来会很乱,就像hello变成了byelo

import sys
#include ctypes if you're on Windows
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleMode(kernel32.GetStdHandle(-11), 7)
#end ctypes

def clearline(msg):
    CURSOR_UP_ONE = ''
    ERASE_LINE = 'x1b[2K'
    sys.stdout.write(CURSOR_UP_ONE)
    sys.stdout.write(ERASE_LINE+'
')
    print(msg, end='
')

#example
ig_usernames = ['beyonce','selenagomez']
for name in ig_usernames:
    clearline("SCRAPING COMPLETE: "+ name)

输出-每一行都将被重写,不显示任何旧文本:

SCRAPING COMPLETE: selenagomez

下一行(在同一行完全重写):

SCRAPING COMPLETE: beyonce

解决方案 14:

根据前面的答案再回答一个。

pbar.py 内容:import sys、shutil、datetime

last_line_is_progress_bar=False


def print2(print_string):
    global last_line_is_progress_bar
    if last_line_is_progress_bar:
        _delete_last_line()
        last_line_is_progress_bar=False
    print(print_string)


def _delete_last_line():
    sys.stdout.write('
')
    sys.stdout.write(' '*shutil.get_terminal_size((80, 20)).columns)
    sys.stdout.write('
')
    sys.stdout.flush()


def update_progress_bar(current, total):
    global last_line_is_progress_bar
    last_line_is_progress_bar=True

    completed_percentage = round(current / (total / 100))
    current_time=datetime.datetime.now().strftime('%m/%d/%Y-%H:%M:%S')
    overhead_length = len(current_time+str(current))+13
    console_width = shutil.get_terminal_size((80, 20)).columns - overhead_length
    completed_width = round(console_width * completed_percentage / 100)
    not_completed_width = console_width - completed_width
    sys.stdout.write('
')

    sys.stdout.write('{}> [{}{}] {} - {}% '.format(current_time, '#'*completed_width, '-'*not_completed_width, current,
                                        completed_percentage),)
    sys.stdout.flush()

脚本用法:

import time
from pbar import update_progress_bar, print2


update_progress_bar(45,200)
time.sleep(1)

update_progress_bar(70,200)
time.sleep(1)

update_progress_bar(100,200)
time.sleep(1)


update_progress_bar(130,200)
time.sleep(1)

print2('some text that will re-place current progress bar')
time.sleep(1)

update_progress_bar(111,200)
time.sleep(1)

print('
') # without 
 next line will be attached to the end of the progress bar
print('built in print function that will push progress bar one line up')
time.sleep(1)

update_progress_bar(111,200)
time.sleep(1)

解决方案 15:

(Python3) 这对我来说很有效。如果您只使用 \010,那么它会留下字符,所以我对其进行了一些调整,以确保它覆盖了那里的内容。这还允许您在第一个打印项之前保留一些内容,并且只删除该项的长度。

print("Here are some strings: ", end="")
items = ["abcd", "abcdef", "defqrs", "lmnop", "xyz"]
for item in items:
    print(item, end="")
    for i in range(len(item)): # only moving back the length of the item
        print(" ", end="") # the trick!
        time.sleep(0.2) # so you can see what it's doing

解决方案 16:

最好覆盖整行,否则如果新行较短,新行将与旧行混合。

import time, os
for s in ['overwrite!', 'the!', 'whole!', 'line!']:
    print(s.ljust(os.get_terminal_size().columns - 1), end="
")
    time.sleep(1)

必须columns - 1在 Windows 上使用。

解决方案 17:

这对我有用,在 Windows 中使用 Spyder 中的 Python 3.7.9:

from IPython.display import clear_output
from time import sleep

def print_and_overwrite(text):
    '''Remember to add print() after the last print that you want to overwrite.'''
    clear_output(wait=True)
    print(text, end='
')

for i in range(15):
    #I print the results backwards (from 15 to 1), to test shorter strings
    message = "Iteration %d out of 15" %(15-i)
    print_and_overwrite(message)
    sleep(0.5)

print() #This stops the overwriting
print("This will be on a new line")

解决方案 18:

无论如何,如果有人想覆盖(清除)之前在 stdout 中打印的许多 ,那么这个答案应该对他有帮助。(感谢 Thijmen Dam 的精彩文章《覆盖以前打印的行》)

在 ANSI 控制台中您可以使用特殊序列:



第一个是抬起光标,第二个是完全删除一行。

清除控制台的示例(Python 3):

LINE_UP = ''
LINE_CLEAR = ''
CONSOLE_HEIGHT = 24 #lines

def clear_console():
    for a in range(CONSOLE_HEIGHT):
        print(LINE_UP, end=LINE_CLEAR, flush=True)

或者最终简单(将清除屏幕并将光标移动到 0,0):

print('', end='', flush=True)

如果你只想定位光标,那么使用这个:

print('[<L>;<C>f', end='', flush=True)

其中<L><C>分别表示线和列。

为您提供一些 ANSI 转义序列的参考

解决方案 19:

根据我在该主题中看到的回复,我制作了一个适用于所有平台的小类。

import sys
import time
    
class PrintSameLine:
    """Class to correctly print on same line.
    """
    def __init__(self):
        self.last_message = ""

    def print_msg(self, msg: str):
        print(" " * len(self.last_message), end="
", flush=True)
        print(msg, end="
", flush=True)
        self.last_message = msg


# Note printing in reverse so you can see how it works
prnt = PrintSameLine()

for i in reversed(range(10)):
    time.sleep(0.5)
    prnt.print_msg("*" * i)

解决方案 20:

我尝试了这个方法,效果很好

import time
for i in range(10):
    print(f'
{i}',end='')
    time.sleep(1)

解决方案 21:

我知道这个问题之前已经有人回答过了,但我找不到一个优雅的解决方案来清除比下一行长的前几行。我正在打印出文件状态,如下所示:

Reading: file1.txt
Adding: file1.txt
Done: file1.txt

因此我创建了一个类,保留了之前的类,并在必要时替换它

class Printer:
    '''
    Clears the previous line and prints the next.
    '''

    max_length: int = 0

    def print_replace(self, nextline):
        '''replace the previous line'''
        print(f'{nextline}  {' ' * max(0, self.max_length - len(nextline))}', end='
')
        self.max_length = max(self.max_length, len(nextline))

    def print_new(self, nextline):
        '''adds to the print stream'''
        print(f'{nextline}  {' ' * max(0, self.max_length - len(nextline))}')
        self.max_length = max(self.max_length, len(nextline))

因此,在读取和写入文件时,它会更新同一行,直到完成。然后完成之后会出现另一行。最后看起来像这样:

Done file1.txt
Done file2.txt
Done file3.txt
Done file4.txt
Done file5.txt
Reading file6.txt

而不是:

Done file1.txttxt
Done file2.txttxt
Done file3.txttxt
Done longer-filename4.txt
Done file5.txtlename4.txt
Reading file6.txt

这样做的好处之一是它不需要睡眠。

printer = Printer()
for x in range(1, 10):
    printer.print_replace(f'Reading file{x}.txt')
    printer.print_replace(f'Writing file{x}.txt')
    printer.print_new(f'Done file{x}.txt')
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1000  
  华为作为全球领先的信息与通信技术(ICT)解决方案提供商,其全球化项目的成功离不开高效的项目管理方法。其中,集成产品开发(IPD)流程是华为项目管理体系的核心组成部分。IPD流程不仅帮助华为在复杂的全球化项目中实现了资源的高效整合,还通过跨部门协作和持续优化,确保了项目的高质量交付。本文将通过具体案例,分析华为IPD流...
IPD测试流程   0  
  IPD(Integrated Product Development)是一种以跨职能团队协作为核心的产品开发流程,旨在通过整合资源、优化流程和提高决策效率,实现产品从概念到市场的快速、高效交付。IPD流程的核心思想是将传统的串行开发模式转变为并行开发模式,通过跨部门协作和早期风险识别,减少开发周期中的浪费和返工。这种方...
IPD流程分为几个阶段   0  
  华为的集成产品开发(IPD)流程是企业项目管理中的经典实践,其核心在于通过跨部门协同实现高效的产品开发。IPD流程强调从市场需求到产品交付的全生命周期管理,而跨部门沟通则是这一流程成功的关键。在华为的实践中,跨部门沟通不仅仅是信息的传递,更是团队协作、目标对齐和资源整合的重要手段。本文将深入探讨IPD流程中的跨部门沟通...
IPD项目管理咨询   0  
  IPD流程全称是集成产品开发(Integrated Product Development),它是一种以客户需求为导向、跨部门协作的产品开发模式。与传统产品开发模式相比,IPD强调在产品开发的早期阶段就整合市场、研发、制造、采购等多个部门的资源和能力,通过并行工程和协同工作来提升开发效率。IPD流程的核心在于打破部门壁...
IPD产品开发流程   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用