在同一行上打印而不是新的一行?

117

基本上,我想做与这个人相反的事情... 嘿嘿。

Python脚本:每次将新行打印到shell而不是更新现有行

我有一个程序告诉我它进行了多少进度。

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete"

如果some_list的长度为50,那么最后一行将被打印50次。我想打印一行并保持更新该行。我知道这可能是你今天读到的最无聊的问题。我只是无法弄清楚需要在Google中输入哪四个单词才能得到答案。

更新!我尝试了mvds的建议,似乎是正确的。 新代码:

print percent_complete,"           \r",

百分比完成只是一个字符串(第一次我进行了抽象,现在我尝试更加字面)。现在的结果是它运行程序,在程序结束之前不打印任何东西,然后仅在一行上打印“100%完成”。

没有换行符(但有逗号,mvds建议的一半),它在结束时什么也不打印。然后打印:

0 percent complete     2 percent complete     3 percent complete     4 percent complete    

等等,现在的问题是有逗号时程序只会在结束后才打印出结果。

使用回车但不带逗号时,输出的行为与两者都不用时完全相同。


你可能还想检查一下 sys.stdout.isatty(),这样当程序不在终端运行时就不会输出这些东西。 - mvds
我正在从终端运行这个...不过想法不错。我相信在某些时候我会需要它的。 - chriscauley
1
背景是,在几种语言中,\n(我们现在省略)作为隐式信号来刷新到标准输出。否则,很多人会感到困惑。顺便说一句。 - mvds
19个回答

2
import time
import sys


def update_pct(w_str):
    w_str = str(w_str)
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(" " * len(w_str))
    sys.stdout.write("\b" * len(w_str))
    sys.stdout.write(w_str)
    sys.stdout.flush()

for pct in range(0, 101):
    update_pct("{n}%".format(n=str(pct)))
    time.sleep(0.1)

\b会将光标向后移动一个空格
所以我们将光标移到行首
然后写入空格以清除当前行 - 写入空格时,光标向前/右移动一位
因此,在写入新数据之前,我们必须将光标移回行首

在Windows cmd上使用Python 2.7进行测试


1
在这些情况下,使用Python 3.x,我使用以下代码:
for ii in range(100):
    print(f"\rPercent: {ii+1} %", end=" "*20)

一些其他答案存在的问题是,如果您的打印字符串在一步中变短,上一个字符串的最后几个字符将不会被覆盖。因此,我使用end =“”* 20以空格覆盖前一行。只需确保20比最长字符串的长度更长即可。

1

适用于 Python 3+

for i in range(5):
    print(str(i) + '\r', sep='', end ='', file = sys.stdout , flush = False)

1

可以尝试这样做:

for i in some_list:
    #do a bunch of stuff.
    print i/len(some_list)*100," percent complete",

(在末尾加上逗号。)

这只是将新文本附加到旧文本的方式(在功能上类似但不美观)。 - chriscauley

0

我自己找到了一种方法来显示倒计时,但也可用于百分比。

import time
#Number of seconds to wait
i=15
#Until seconds has reached zero
while i > -1:
    #Ensure string overwrites the previous line by adding spaces at end
    print("\r{} seconds left.   ".format(i),end='')
        time.sleep(1)
        i-=1
    print("") #Adds newline after it's done

只要'/r'后面的内容与之前的字符串长度相同或更长(包括空格),它就会覆盖在同一行上。只需确保包含end='',否则它将打印到新行。希望这有所帮助!

0

基于Remi答案,对于Python 2.7+使用以下代码:

from __future__ import print_function
import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    import sys
    n = 0
    while n < total:
        done = '#' * (n + 1)
        todo = '-' * (total - n - 1)
        s = '<{0}>'.format(done + todo)
        if not todo:
            s += '\n'
        if n > 0:
            s = '\r' + s
        print(s, end='\r')
        sys.stdout.flush()
        yield n
        n += 1


# example for use of status generator
for i in range_with_status(50):
    time.sleep(0.2)

0

对于用于任何list而不仅仅是int,并且利用您控制台窗口的整个宽度而不跨越到新行的Python 3.6+,您可以使用以下方法:

请注意:请知悉,函数get_console_with()仅适用于基于Linux的系统,因此您必须重写它以在Windows上运行。

import os
import time

def get_console_width():
    """Returns the width of console.

    NOTE: The below implementation works only on Linux-based operating systems.
    If you wish to use it on another OS, please make sure to modify it appropriately.
    """
    return int(os.popen('stty size', 'r').read().split()[1])


def range_with_progress(list_of_elements):
    """Iterate through list with a progress bar shown in console."""

    # Get the total number of elements of the given list.
    total = len(list_of_elements)
    # Get the width of currently used console. Subtract 2 from the value for the
    # edge characters "[" and "]"
    max_width = get_console_width() - 2
    # Start iterating over the list.
    for index, element in enumerate(list_of_elements):
        # Compute how many characters should be printed as "done". It is simply
        # a percentage of work done multiplied by the width of the console. That
        # is: if we're on element 50 out of 100, that means we're 50% done, or
        # 0.5, and we should mark half of the entire console as "done".
        done = int(index / total * max_width)
        # Whatever is left, should be printed as "unfinished"
        remaining = max_width - done
        # Print to the console.
        print(f'[{done * "#"}{remaining * "."}]', end='\r')
        # yield the element to work with it
        yield element
    # Finally, print the full line. If you wish, you can also print whitespace
    # so that the progress bar disappears once you are done. In that case do not
    # forget to add the "end" parameter to print function.
    print(f'[{max_width * "#"}]')


if __name__ == '__main__':
    list_of_elements = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
    for e in range_with_progress(list_of_elements):
        time.sleep(0.2)


0
针对对象"pega",它提供了StartRunning()、StopRunning()、getIsRunning()布尔值和getProgress100()整数值,返回值在0到100的范围内,这为运行时提供了文本进度条...
now = time.time()
timeout = now + 30.0
last_progress = -1

pega.StartRunning()

while now < timeout and pega.getIsRunning():
    time.sleep(0.5)
    now = time.time()

    progress = pega.getTubProgress100()
    if progress != last_progress:
        print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", end='', flush=True)
        last_progress = progress

pega.StopRunning()

progress = pega.getTubProgress100()
print('\r'+'='*progress+'-'*(100-progress)+' ' + str(progress) + "% ", flush=True)

0

如果您正在使用Python 3,那么这是适合您的,并且它确实有效。

print(value , sep='',end ='', file = sys.stdout , flush = False)

即使“value”是一个“pandas”数据框,它也能正常工作吗? - McLovin

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