Як записати вихід на одне місце на консолі?


158

Я новачок у python і пишу кілька сценаріїв для автоматизації завантаження файлів з FTP-серверів і т. Д. Я хочу показати хід завантаження, але хочу, щоб він залишався в тому самому положенні, як:

вихід:

Завантаження файлу FooFile.txt [47%]

Я намагаюся уникати чогось подібного:

     Downloading File FooFile.txt [47%]
     Downloading File FooFile.txt [48%]
     Downloading File FooFile.txt [49%]

Як я повинен робити це?


Дублікат : Як я можу надрукувати над поточним рядком у програмі командного рядка?


1
Вас може зацікавити цей простий у користуванні модуль - це текстовий рядок. pypi.python.org/pypi/progressbar/2.2
Вім

Відповіді:


254

Ви також можете скористатися поверненням перевезення:

sys.stdout.write("Download progress: %d%%   \r" % (progress) )
sys.stdout.flush()

13
Дуже поширене і просте рішення. Примітка: якщо ваша лінія більше ширини вашого терміналу, це стає некрасивим.
ефемія

5
Я також повинен був додати дзвінок на sys.stdout.flush (), щоб курсор не відскакував
scottm

19
Чи можливо це зробити кількома рядками? Скажімо, у мене є три різних завантаження, і я хочу показати хід кожної з них у своєму рядку.
EarlCrapstone

11
Мені подобається поставити \rна початку рядка і додати а, \x1b[Kщоб очистити попередній текст.
серпня

11
Здається, що найпростішим рішенням для python 3 (як зазначено у відповідях нижче) є: print("sample text", end='\r", flush=True)
Сайрус

35

Пітон 2

Мені подобається таке:

print 'Downloading File FooFile.txt [%d%%]\r'%i,

Демонстрація:

import time

for i in range(100):
    time.sleep(0.1)
    print 'Downloading File FooFile.txt [%d%%]\r'%i,

Пітон 3

print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

Демонстрація:

import time

for i in range(100):
    time.sleep(0.1)
    print('Downloading File FooFile.txt [%d%%]\r'%i, end="")

Консоль відладчика PyCharm з Python 3

# On PyCharm Debugger console, \r needs to come before the text.
# Otherwise, the text may not appear at all, or appear inconsistently.
# tested on PyCharm 2019.3, Python 3.6

import time

print('Start.')
for i in range(100):
    time.sleep(0.02)
    print('\rDownloading File FooFile.txt [%d%%]'%i, end="")
print('\nDone.')

9
використовувати це для python 3+: print ('Завантаження файлу FooFile.txt [% d %%] \ r'% i, end = "")
hkoosha

На консолі налагодження PyCharm Debugger потрібно вийти перед текстом. В іншому випадку текст може взагалі не з’являтися або з’являтися непослідовно. Я додав версію, яка працює для мене як редагування, тому що я не міг написати багаторядковий код у цій відповіді. Я поклав це на свою суть, щоб люди могли переглядати його, поки редакція чекає затвердження: gist.github.com/yulkang/40168c7729a7a7b96d0116d8b1bc26df
Юл Кан

"\ r" в кінці рядка працює для мене на консолі налагодження на PyCharm 2020.1 (PyCharm 2020.1.2 (Community Edition); Build # PC-201.7846.77, побудований 31 травня 2020 року).
battey

28

Використовуйте бібліотеку обробки терміналів, наприклад модуль curses :

Модуль curses забезпечує інтерфейс до бібліотеки прокльонів, стандарт де-факто для портативного розширеного управління терміналами.


1
Не доступно для Windows.
Дієго Херранц

3
@Diego зараз існує підтримка бібліотеки модулів прокльонів у Windows. см stackoverflow.com/a/19851287/1426237
Plexico

15

Надрукуйте символ зворотної області \bкілька разів, а потім перезапишіть старий номер новим номером.


Що цікаво, я не думав робити це так.
Кріс Баланс

Мені це подобається, тому що він не очищає попередні команди (якщо у вас є кілька етапів, які ви бажаєте залишити на екрані)
Nathan Donnellan

3
Використання повернення каретки (наприклад print 'Downloading.... \r') також не очищає попередні дані, але це заважає знати, як далеко робити резервну копію.
cod3monk3y

8
#kinda like the one above but better :P

from __future__ import print_function
from time import sleep

for i in range(101):
  str1="Downloading File FooFile.txt [{}%]".format(i)
  back="\b"*len(str1)
  print(str1, end="")
  sleep(0.1)
  print(back, end="")

Чому це краще, ніж зазначено вище (я Python n00b, тому, вибачте, будь ласка, моє незнання :-))?
Відшкодування BalinKingOfMoria відновити

7

Для Python 3xx:

import time
for i in range(10):
    time.sleep(0.2) 
    print ("\r Loading... {}".format(i)+str(i), end="")

4

Акуратне рішення, яке працює для мене:

from __future__ import print_function
import sys
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is {}% complete      ".format(perc), end='\r')
    sys.stdout.flush()
print("")

Це sys.stdout.flushважливо, інакше він стає дійсно незграбним, і значення print("")для виходу з циклу також важливо.

ОНОВЛЕННЯ : Як зазначено в коментарях, printтакож є flushаргумент. Отже, також буде працювати наступне:

from __future__ import print_function
for i in range(10**6):
    perc = float(i) / 10**6 * 100
    print(">>> Download is {}% complete      ".format(perc), end='\r', flush=True)
print("")

1
У сучасному мові Python, ви можете поставляти ARG з flush=Trueдо print, так що немає ніякої необхідності в додатковому sys.stdout.flush()виклику.
PM 2Ring

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.