Como escrevo a saída no mesmo local no console?

158

Sou iniciante no python e estou escrevendo alguns scripts para automatizar o download de arquivos de servidores FTP, etc. Quero mostrar o andamento do download, mas quero que ele permaneça na mesma posição, como:

resultado:

Fazendo o download do arquivo FooFile.txt [47%]

Estou tentando evitar algo assim:

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

Como devo fazer isso?


Duplicar : Como posso imprimir sobre a linha atual em um aplicativo de linha de comando?

escocês
fonte
1
você pode estar interessado neste módulo fácil de usar, é uma barra de progresso de texto. pypi.python.org/pypi/progressbar/2.2
wim

Respostas:

254

Você também pode usar o retorno de carro:

sys.stdout.write("Download progress: %d%%   \r" % (progress) )
sys.stdout.flush()
codelogic
fonte
13
Solução muito comum e simples. Nota: se sua linha for maior que a largura do seu terminal, isso ficará feio.
ephemient
5
Eu também tive que adicionar uma chamada para sys.stdout.flush () para que o cursor não saltar ao redor
scottm
19
É possível fazer isso com várias linhas? Digamos que tenho três downloads diferentes e quero mostrar o progresso de cada um em sua própria linha.
fácil
11
Eu gosto de colocar o \rno início da linha e adicionar um \x1b[Kpara limpar o texto anterior.
Augurar
11
Parece que a solução mais simples para python 3 (como mencionado em respostas abaixo) é: print("sample text", end='\r", flush=True)
Cyrus
35

Python 2

Eu gosto do seguinte:

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

Demo:

import time

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

Python 3

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

Demo:

import time

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

Console do depurador PyCharm com 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.')
RSabet
fonte
9
usar isso para python 3+: print ( 'download FooFile.txt arquivo [% d %%] \ r' % i, end = "")
hkoosha
No console do PyCharm Debugger, é necessário vir antes do texto. Caso contrário, o texto pode não aparecer ou aparecer inconsistentemente. Eu adicionei a versão que funciona para mim como uma edição, porque não consegui escrever código de várias linhas nesta resposta. Coloquei na minha essência para que as pessoas possam vê-la enquanto a edição aguarda aprovação: gist.github.com/yulkang/40168c7729a7a7b96d0116d8b1bc26df
Yul Kang
"\ r" no final da string funciona para mim no console do depurador no PyCharm 2020.1 (PyCharm 2020.1.2 (Community Edition); Build # PC-201.7846.77, criada em 31 de maio de 2020).
battey 11/06
28

Use uma biblioteca de manipulação de terminal como o módulo de maldições :

O módulo curses fornece uma interface para a biblioteca curses, o padrão de fato para o manuseio avançado de terminais portáteis.

gimel
fonte
1
Não disponível para Windows.
Diego Herranz
3
@ Diego agora existe uma biblioteca de suporte para o módulo maldições no Windows. Veja stackoverflow.com/a/19851287/1426237
Plexico
15

Imprima o caractere de backspace \bvárias vezes e substitua o número antigo pelo novo número.

Zach Scrivena
fonte
interessante, eu não tinha pensado em fazer dessa maneira.
31520 Chris Ballance
I como este, porque ele não limpar comandos anteriores (se você tiver vários estágios deseja sair na tela)
Nathan Donnellan
3
O uso do retorno de carro (por exemplo print 'Downloading.... \r') também não limpa os dados anteriores, mas evita a necessidade de saber a que distância o backup será realizado.
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="")
Christian Calderon
fonte
Por que isso é melhor do que o descrito acima (eu sou um Python n00b, então, desculpe minha ignorância :-))?
BalinKingOfMoria Reinstala CMs
7

Para Python 3xx:

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

Uma solução interessante que está funcionando para mim é:

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("")

O sys.stdout.flushé importante, caso contrário, fica realmente desajeitado e a print("")saída de loop on também é importante.

UPDATE : Como mencionado nos comentários, printtambém tem um flushargumento. Portanto, o seguinte também funcionará:

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("")
Michael Hall
fonte
1
No Python moderno, você pode fornecer um argumento de flush=Trueto print, para que não haja necessidade de uma sys.stdout.flush()chamada extra .
PM 2Ring
0
x="A Sting {}"
   for i in range(0,1000000):
y=list(x.format(i))
print(x.format(i),end="")

for j in range(0,len(y)):
    print("\b",end="")
Malaio Hazarika
fonte