Как перезаписать предыдущую печать на stdout в python?

Если бы у меня был следующий код:

for x in range(10):
     print x

Я бы получил вывод

1
2
etc..

Я хотел бы сделать это вместо печати новой строки, я хочу заменить предыдущее значение и перезаписать его новым значением в той же строке.

Ответ 1

Один из способов - использовать символ возврата каретки ('\r'), чтобы вернуться к началу строки, не переходя к следующей строке:

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

Запятая в конце инструкции печати говорит, что она не переходит к следующей строке. Последний оператор печати переходит к следующей строке, поэтому ваше приглашение не перезапишет ваш окончательный результат.

Ответ 3

@Mike DeSimone ответ, вероятно, будет работать большую часть времени. Но...

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

-> 1bc

Это связано с тем, что '\r' возвращается только в начало строки, но не очищает вывод.

EDIT: лучшее решение (чем мое прежнее предложение ниже)

Если для вас достаточно поддержки POSIX, следующее очистит текущую строку и оставьте курсор в начале:

print '\x1b[2K\r',

Он использует код выхода ANSI для очистки терминальной линии. Более подробную информацию можно найти в wikipedia и в этот отличный разговор.

Старый ответ

Решение (не очень хорошее), которое я нашел, выглядит следующим образом:

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

-> 1

Одно из преимуществ заключается в том, что он будет работать и на окнах.

Ответ 4

У меня был тот же вопрос, прежде чем вы посещали эту тему. Для меня sys.stdout.write работал только в том случае, если я правильно очищаю буфер i.e.

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

Без промывки результат печатается только в конце script

Ответ 5

Подавление новой строки и печать \r.

print 1,
print '\r2'

или напишите в stdout:

sys.stdout.write('1')
sys.stdout.write('\r2')

Ответ 6

Я не мог заставить какие-либо решения на этой странице работать на IPython, но небольшое отклонение от решения @Mike-Desimone выполнило задание: вместо того, чтобы завершить линию с возвратом каретки, запустите линию с возвратом каретки:

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

Кроме того, для этого подхода не требуется второй оператор печати. ​​

Ответ 7

Попробуй это:

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

Это сработало для меня. Часть end="\r" заставляет перезаписать предыдущую строку.

ПРЕДУПРЕЖДЕНИЕ!

Если вы распечатаете hi, а затем распечатаете hello используя \r, вы получите hillo потому что выходные данные hillo поверх предыдущих двух букв. Если вы распечатываете hi с пробелами (которые здесь не отображаются), то выводится hi. Чтобы это исправить, распечатайте пробелы, используя \r.

Ответ 8

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

time.sleep(0.5) показывает, как предыдущий вывод стирается, а новый вывод печатается "\ r", когда он находится в начале сообщения печати, он удалит предыдущий вывод перед новым выводом.

Ответ 9

Принятый ответ не идеален. Строка, которая была напечатана первой, останется там, и если ваш второй оттиск не покрывает всю новую строку, вы получите текст мусора.

Чтобы проиллюстрировать проблему, сохраните этот код как скрипт и запустите его (или просто посмотрите):

import time

n = 100
for i in range(100):
    for j in range(100):
        print("Progress {:2.1%}".format(j / 100), end="\r")
        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="\r")
        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%

Ответ 10

Это работает на Windows и Python 3.6

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

Ответ 11

Здесь более чистая, более "подключи и работай" версия @Nagasaki45. В отличие от многих других ответов здесь, он работает правильно со строками разной длины. Это достигается путем очистки строки с таким же количеством пробелов, как длина последней напечатанной строки. Также будет работать на Windows.

def print_statusline(msg: str):
    last_msg_length = len(print_statusline.last_msg) if hasattr(print_statusline, 'last_msg') else 0
    print(' ' * last_msg_length, end='\r')
    print(msg, end='\r')
    sys.stdout.flush()  # Some say they needed this, I didn't.
    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)

Ответ 12

Для создания загрузчика я использовал следующее:

for i in range(10):
    print(i*'.', end='\r')

Ответ 13

(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("\010 \010", end="") # the trick!
        time.sleep(0.2) # so you can see what it doing

Ответ 14

Я немного удивлен, что никто не использует символ возврата. Вот тот, который использует это.

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('\b')

Ответ 15

Вот мое решение! 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 = '\033[K'
    ERASE_LINE = '\x1b[2K'
    sys.stdout.write(CURSOR_UP_ONE)
    sys.stdout.write(ERASE_LINE+'\r')
    print(msg, end='\r')

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

Вывод - каждая строка будет переписана без какого-либо старого текста, показывающего:

SCRAPING COMPLETE: selenagomez

Следующая строка (полностью переписана в той же строке):

SCRAPING COMPLETE: beyonce

Ответ 16

Еще один ответ, основанный на предыдущих ответах.

Содержание 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('\b\b\r')
    sys.stdout.write(' '*shutil.get_terminal_size((80, 20)).columns)
    sys.stdout.write('\b\r')
    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('\b\b\r')

    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('\n') # without \n 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)

Ответ 17

Вот простой код, который может быть вам полезен!

import sys
import time

for i in range(10):
    sys.stdout.write("\r" + i)
    sys.stdout.flush()
    time.sleep(1)