Друкувати на тому самому рядку, а не на новому рядку в python


85

В основному я хочу зробити протилежне тому, що зробив цей хлопець ... хе-хе.

Python Script: кожен раз друкуйте новий рядок для оболонки, а не оновлюйте існуючий рядок

У мене є програма, яка повідомляє мені, наскільки це далеко.

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

Я запускаю це з терміналу ... Хороша думка. Я впевнений, що мені це колись знадобиться.
chriscauley

1
фон, до речі, в тому, що в декількох мовах символ \ n (який ми зараз опускаємо) служить неявним сигналом для переходу на stdout. Бо інакше багато людей будуть розгублені.
mvds

Відповіді:


85

Це називається поверненням каретки, або \r

Використовуйте

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

Кома забороняє друку додавати новий рядок. (а пробіли утримуватимуть рядок від попереднього виводу)

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


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

Так близько ... Я оновлю запитання з результатом цього.
chriscauley

2
@dustynachos: Хе, забув про цю зморшку. Дивіться питання буферизації вихідних даних Python: stackoverflow.com/questions/107705/python-output-buffering
Ніколас Найт

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

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

35

Для мене спрацювало поєднання відповідей Ремі та Сіріусда:

from __future__ import print_function
import sys

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

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

2
це позбавляє від нового рядка, але не дозволяє перезаписувати, що, на мою думку, хоче автор.
bgenchel

1
@bgenchel, що використовується з '\ r' (як у зразку коду), він робить саме те, що хоче ОП
Майло Вілондек,

19

У Python 3.3+ вам це не потрібно sys.stdout.flush(). print(string, end='', flush=True)робіт.

Тому

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

замінить 'foo' на 'bar'.


2
Це працює, за умови, що друкований текст закінчується символом "\r".
бли

13

для консолі вам напевно знадобиться

sys.stdout.flush()

для примусового оновлення. Я думаю, що використання ,в print дозволить блокувати stdout від змивання і якось не оновиться


Термінатор лише оновлював рядок кожні 30 секунд, використовуючи для мене print ("...", end = '\ r'), якщо тільки я не запустив цю команду відразу після оператора print. Дякую
Bryce Guinta

4

Пізно до гри - але оскільки жодна з відповідей не спрацювала для мене (я не перепробував їх усіх), і я не раз зустрічав цю відповідь у своєму пошуку ... У python 3 це рішення досить елегантне і я вважаю, робить саме те, що шукає автор, він оновлює одне твердження в тому ж рядку. Зверніть увагу, можливо, вам доведеться зробити щось особливе, якщо рядок зменшується, а не зростає (наприклад, можливо, зробіть рядок фіксованою довжиною з пробілами в кінці)

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

найпростіший і найчистіший варіант для python => 3,6
DaveR

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",

(З комою в кінці.)


Це просто додає новий текст до старого (функціонально схожий, але негарний).
chriscauley

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

На основі відповіді 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

Для Python 3.6+і для будь-якого, listа не просто ints, а також використовуючи всю ширину вікна вашої консолі і не переходячи до нового рядка, ви можете використовувати наступне:

Примітка: будь ласка, повідомте, що функція 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

Для Python 3+

for i in range(5):
    print(str(i) + '\r', 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', має однакову довжину або довше (включаючи пробіли), ніж попередній рядок, воно буде перезаписано його в одному рядку. Просто переконайтеся, що ви вказали end = '', інакше він надрукується на новий рядок. Сподіваюся, це допоможе!


0

для об'єкта "pega", який забезпечує StartRunning (), StopRunning (), boolean 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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.