Печатать до той же строки, а не с новой строки?


89

По сути, я хочу сделать противоположное тому, что сделал этот парень ... хе-хе.

Сценарий Python: каждый раз выводить новую строку в оболочку, а не обновлять существующую строку

У меня есть программа, которая сообщает мне, как далеко она продвинулась.

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

Итак, если бы len (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 05

Я запускаю это с терминала ... хорошая мысль. Я уверен, что когда-нибудь мне это понадобится.
Крисколи

1
фон, кстати, таков, что на некоторых языках \ n (который мы сейчас опускаем) служит неявным сигналом для сброса на стандартный вывод. В противном случае многие люди запутаются.
mvds 06

Ответы:


86

Это называется возвратом каретки или \r

Использовать

print i/len(some_list)*100," percent complete         \r",

Запятая предотвращает добавление новой строки при печати. (и пробелы будут держать строку чистой от предыдущего вывода)

Кроме того, не забудьте завершить, print ""чтобы получить хотя бы завершающую новую строку!


12
Просто убедитесь, что вы всегда печатаете тот же объем данных (или больше, чем любой предыдущий) в строке, иначе в конце вы получите беспорядок.
Николас Найт

Так близко ... Я обновлю вопрос с результатом этого.
Крисколи, 05

2
@dustynachos: Хех, забыл про эту морщинку. См. Вопрос о буферизации вывода Python: stackoverflow.com/questions/107705/python-output-buffering
Николас Найт,

1
@dustynachos: (или просто используйте sys.stdout.flush () после каждого вызова печати, это может быть лучше, если вам не нужна буферизация вывода для остальной части вашей программы)
Николас Найт,

2
это не работает для меня. Я на самом деле пробовал это много раз, и это никогда не помогало мне. Я использую iterm2 на Mac, но большую часть времени я использую ssh на сервере Linux. Я никогда не находил действительно работающего метода.
bgenchel 06

33

Из python 3.x вы можете:

print('bla bla', end='')

(который также можно использовать в Python 2.6 или 2.7, поместив from __future__ import print_functionвверху вашего скрипта / модуля)

Пример панели прогресса консоли Python:

import time

# status generator
def range_with_status(total):
    """ iterate from 0 to total and show progress in console """
    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='')
        yield n
        n+=1

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

\ R, похоже, также добавляет новую строку
fccoelho

3
это избавляет от новой строки, но не позволяет перезаписывать, что я думаю, что автор хочет.
bgenchel 06

1
@bgenchel используется с '\ r' (как в примере кода), он делает именно то, что хочет OP,
Майло Велондек

33

Для меня сработала комбинация ответов Реми и Сириусда:

from __future__ import print_function
import sys

print(str, end='\r')
sys.stdout.flush()

Устаревший .. Начиная с Python 3.8.5 для меня работает только то, что работает: print ("some string", end = '\ r')
rroger

23

В Python 3.3+ вам не нужно sys.stdout.flush(). print(string, end='', flush=True)работает.

Так

print('foo', end='')
print('\rbar', end='', flush=True)

заменит 'foo' на 'bar'.


2
Это работает при условии, что печатный текст оканчивается на "\r".
bli

13

для консоли вам, вероятно, понадобится

sys.stdout.flush()

принудительно обновить. Я думаю, что использование ,в печати заблокирует stdout от промывки и каким-то образом не будет обновляться


Терминатор обновлял строку только каждые 30 секунд при использовании для меня print ("...", end = '\ r'), если я не запустил эту команду сразу после оператора печати. Спасибо
Bryce Guinta

4

Поздно к игре, но поскольку ни один из ответов у меня не сработал (я не пробовал их все), и я встречал этот ответ более одного раза в своем поиске ... В python 3 это решение довольно элегантно и я считаю, что он делает именно то, что ищет автор, он обновляет одно утверждение в той же строке. Обратите внимание: возможно, вам придется сделать что-то особенное, если строка сжимается, а не растет (например, возможно, сделать строку фиксированной длины с заполненными пробелами в конце)

if __name__ == '__main__':
    for i in range(100):
        print("", end=f"\rPercentComplete: {i} %")
        time.sleep(0.2)


3

Это работает для меня, однажды взломал его, чтобы увидеть, возможно ли это, но на самом деле никогда не использовался в моей программе (графический интерфейс намного лучше):

import time
f = '%4i %%'
len_to_clear = len(f)+1
clear = '\x08'* len_to_clear
print 'Progress in percent:'+' '*(len_to_clear),
for i in range(123):
    print clear+f % (i*100//123),
    time.sleep(0.4)
raw_input('\nDone')

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

Попробуйте так:

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

(С запятой в конце.)


Это просто добавляет новый текст к старому (функционально похожему, но некрасивому).
Крисколи, 05

1

Если вы используете Spyder, строки будут печататься непрерывно со всеми предыдущими решениями. Способ избежать этого - использовать:

for i in range(1000):
    print('\r' + str(round(i/len(df)*100,1)) + '% complete', end='')
    sys.stdout.flush()

Для меня это было единственное рабочее решение (Python 3.8, Windows, PyCharm).
z33k


0

На основе ответа Реми для 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

Для Python 3.6+и для любого, listа не толькоint s, а также для использования всей ширины окна консоли и без перехода на новую строку вы можете использовать следующее:

Примечание: имейте в виду, что эта функция 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

Если вы используете Python 3, то это для вас, и это действительно работает.

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

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', имеет такую ​​же длину или больше (включая пробелы), чем предыдущая строка, оно будет перезаписывать его в той же строке. Просто убедитесь, что вы добавили конец = '', иначе он будет печататься до новой строки. Надеюсь, это поможет!


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

По состоянию на конец 2020 года и Python 3.8.5 на консоли Linux для меня работает только это:

print('some string', end='\r')

Кредит принадлежит: Этот пост

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.