Imprime na mesma linha e não em uma nova linha em python


89

Basicamente, eu quero fazer o oposto do que esse cara fez ... hehe.

Script Python: imprime uma nova linha a cada vez para o shell em vez de atualizar a linha existente

Eu tenho um programa que está me dizendo o quão longe está.

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

Então, se len (alguma_lista) fosse 50, eu imprimiria a última linha 50 vezes. Quero imprimir uma linha e continuar atualizando essa linha. Eu sei, eu sei que esta é provavelmente a pergunta mais idiota que você vai ler o dia todo. Simplesmente não consigo descobrir as quatro palavras que preciso colocar no google para obter a resposta.

Atualizar! Eu tentei a sugestão do mvds que PARECEU certa. O novo código

print percent_complete,"           \r",

O percentual completo é apenas uma string (eu estava abstraindo da primeira vez, agora estou tentando ser literal). O resultado agora é que ele executa o programa, não imprime NADA até que o programa termine e imprime "100 por cento concluído" em uma e somente uma linha.

Sem o retorno de carro (mas com a vírgula, metade da sugestão do mvds) ele não imprime nada até o final. E então imprime:

0 percent complete     2 percent complete     3 percent complete     4 percent complete    

E assim por diante. Portanto, o novo problema é que, com a vírgula, ela não imprime até que o programa seja concluído.

Com o retorno de carro e sem vírgula, ele se comporta da mesma forma que nenhum.


Você também pode querer verificar sys.stdout.isatty()para não cuspir essas coisas quando não estiver executando em um terminal.
mvds de

Estou executando isso de um terminal ... uma boa idéia embora. Tenho certeza que vou precisar disso em algum momento.
chriscauley

1
o pano de fundo é, aliás, que em várias linguagens o \ n (que agora omitimos) serve como um sinal implícito para limpar para stdout. Do contrário, muitas pessoas ficarão confusas.
mvds de

Respostas:


86

É chamado de retorno de carro, ou \r

Usar

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

A vírgula impede a impressão de adicionar uma nova linha. (e os espaços manterão a linha limpa da saída anterior)

Além disso, não se esqueça de terminar com um print ""para obter pelo menos uma nova linha de finalização!


12
Apenas certifique-se de sempre imprimir a mesma quantidade de dados (ou mais do que qualquer impressão anterior) na linha, caso contrário, você acabará com problemas no final.
Nicholas Knight

Tão perto ... Vou atualizar a pergunta com o resultado disso.
chriscauley

2
@dustynachos: Heh, esqueci dessa ruga. Consulte a pergunta sobre buffer de saída do Python: stackoverflow.com/questions/107705/python-output-buffering
Nicholas Knight

1
@dustynachos: (ou apenas use sys.stdout.flush () após cada chamada de impressão, que pode ser melhor se você não se importar com o buffer de saída para o resto do seu programa)
Nicholas Knight

2
isso não funciona para mim. Na verdade, já tentei várias vezes e nunca funcionou para mim. Estou usando iterm2 em um mac, mas estou usando ssh em um servidor Linux na maioria das vezes. Nunca encontrei um método para fazer isso que realmente funcione.
bgenchel

33

No python 3.x, você pode fazer:

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

(que também pode ser usado no Python 2.6 ou 2.7, colocando from __future__ import print_functionno topo do seu script / módulo)

Exemplo de barra de progresso do console 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)

O \ r parece adicionar uma nova linha também
fccoelho

3
isso elimina a nova linha, mas não permite sobrescrever, que acho que é o que o autor deseja.
bgenchel

1
@bgenchel usado com '\ r' (como no exemplo de código) faz exatamente o que OP deseja
Milo Wielondek

33

Para mim, o que funcionou foi uma combinação das respostas de Remi e Siriusd:

from __future__ import print_function
import sys

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

Desatualizado .. No Python 3.8.5, para mim, apenas isso funciona: print ("alguma string", end = '\ r')
rroger

23

No Python 3.3+ você não precisa sys.stdout.flush(). print(string, end='', flush=True)trabalho.

então

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

irá sobrescrever 'foo' por 'bar'.


2
Funciona, desde que o texto impresso termine com um "\r".
bli de

13

para console você provavelmente precisará

sys.stdout.flush()

para forçar a atualização. Eu acho que usar ,em impressão irá bloquear o fluxo de saída padrão e de alguma forma ele não atualizará


O Terminator estava apenas atualizando a linha a cada 30 segundos ao usar print ("...", end = '\ r') para mim, a menos que eu execute este comando imediatamente após a instrução print. Obrigado
Bryce Guinta

4

Atrasado para o jogo - mas como nenhuma das respostas funcionou para mim (não tentei todas) e encontrei esta resposta mais de uma vez em minha pesquisa ... Em python 3, esta solução é muito elegante e acredito que faz exatamente o que o autor está procurando, atualiza uma única declaração na mesma linha. Observe, você pode ter que fazer algo especial se a linha encolher em vez de crescer (como, talvez, tornar a corda um comprimento fixo com espaços preenchidos no final)

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

1
opção mais simples e limpa para python => 3,6
DaveR

3

Isso funciona para mim, hackeado uma vez para ver se é possível, mas nunca realmente usei no meu programa (GUI é muito mais agradável):

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)

\birá mover a localização do cursor um espaço para trás
Então nós o movemos de volta até o início da linha
Nós então escrevemos espaços para limpar a linha atual - conforme escrevemos os espaços, o cursor se move para frente / direita em um
Então temos para mover o cursor de volta ao início da linha antes de escrevermos nossos novos dados

Testado em Windows cmd usando Python 2.7


1

Experimente assim:

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

(Com uma vírgula no final.)


Isso apenas acrescenta o novo texto ao antigo (funcionalmente semelhante, mas feio).
chriscauley

1

Se você estiver usando o Spyder, as linhas serão impressas continuamente com todas as soluções anteriores. Uma maneira de evitar isso é usar:

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

Esta foi a única solução que funcionou para mim (Python 3.8, Windows, PyCharm).
z33k

1

Para Python 3+

for i in range(5):
    print(str(i) + '\r', sep='', end ='', file = sys.stdout , flush = False)

0

Com base na resposta de Remi para Python 2.7+usar isto:

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

Para Python 3.6+e para qualquer, em listvez de apenas ints, além de usar toda a largura da janela do console e não passar para uma nova linha, você pode usar o seguinte:

nota: esteja ciente de que a função get_console_with()funcionará apenas em sistemas baseados em Linux e, como tal, você terá que reescrevê-la para funcionar no 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

Se você estiver usando Python 3, ele é para você e realmente funciona.

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

0

Só descobri isso sozinho para mostrar uma contagem regressiva, mas também funcionaria para uma porcentagem.

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

Desde que o que vier depois de '/ r' tiver o mesmo comprimento ou mais (incluindo espaços) que a string anterior, ele será sobrescrito na mesma linha. Apenas certifique-se de incluir end = '', caso contrário, ele será impresso em uma nova linha. Espero que ajude!


0

para o objeto "pega" que fornece StartRunning (), StopRunning (), getIsRunning () booleano e getProgress100 () inteiro retornando valor no intervalo de 0 a 100, isso fornece uma barra de progresso de texto durante a execução ...

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

No final de 2020 e Python 3.8.5 no console do Linux para mim, apenas isso funciona:

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

O crédito vai para: Esta postagem

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.