Imprimir em uma linha dinamicamente


306

Eu gostaria de fazer várias declarações que fornecem saída padrão sem ver novas linhas entre as declarações.

Especificamente, suponha que eu tenha:

for item in range(1,100):
    print item

O resultado é:

1
2
3
4
.
.
.

Como é que isso se parece:

1 2 3 4 5 ...

Melhor ainda, é possível imprimir o número único sobre o último número, para que apenas um número esteja na tela por vez?


Respostas:


482

Mude print itempara:

  • print item, no Python 2.7
  • print(item, end=" ") em Python 3

Se você deseja imprimir os dados dinamicamente, use a seguinte sintaxe:

  • print(item, sep=' ', end='', flush=True) em Python 3

Em http://docs.python.org/reference/simple_stmts.html#print :> Um '\n'caractere é escrito no final, a menos que a printinstrução termine com uma vírgula. Essa é a única ação se a instrução contiver apenas a palavra-chave print.
eWall

5
FYI: print (item, end = "") pode ser usado no Python2.7 adicionando 'da futura importação print_function' na parte superior do arquivo.
Hec

2
Mas flushnão funciona com from __future__ import print_functioninfelizmente.
Timmmm

@ewall se eu fosse fazer print(item, end=", ")isso, então também adiciona ,para o último item como fazer impedi-lo de adição ,para o último item
MarcoBianchi

@SamirTendulkar Se você estiver usando um loop for como a pergunta original, você poderia fazer um caso especial para lidar com o último item na lista de forma diferente ...
eWall

156

A propósito ...... Como atualizá-lo sempre, para que ele imprima mi em um só lugar, basta alterar o número.

Em geral, a maneira de fazer isso é com os códigos de controle do terminal . Este é um caso particularmente simples, para o qual você só precisa de um caractere especial: U + 000D CARRIAGE RETURN, escrito '\r'em Python (e em muitos outros idiomas). Aqui está um exemplo completo com base no seu código:

from sys import stdout
from time import sleep
for i in range(1,20):
    stdout.write("\r%d" % i)
    stdout.flush()
    sleep(1)
stdout.write("\n") # move the cursor to the next line

Algumas coisas sobre isso que podem ser surpreendentes:

  • o \r vai no início da string para que, enquanto o programa estiver em execução, o cursor esteja sempre após o número. Isso não é apenas cosmético: alguns emuladores de terminal ficam muito confusos se você fizer o contrário.
  • Se você não incluir a última linha, depois que o programa terminar, seu shell imprimirá seu prompt sobre o número.
  • O stdout.flushé necessário em alguns sistemas ou você não obterá nenhuma saída. Outros sistemas podem não exigir, mas não causam danos.

Se você achar que isso não funciona, a primeira coisa que você deve suspeitar é que o seu emulador de terminal está com erros. O programa vttest pode ajudá-lo a testá-lo.

Você pode substituir o stdout.writepor uma printdeclaração, mas eu prefiro não misturar printcom o uso direto de objetos de arquivo.


O que meen flush () funciona? Porque funciona para mim sem essa função!
Pol

1
Normalmente, os objetos de arquivo do Python acumulam dados para que possam enviá-los ao sistema operacional em grandes partes. É isso que você deseja para acessar arquivos no disco, geralmente, mas isso interfere nesse tipo de tarefa. flush()força um arquivo a enviar o que for necessário para o sistema operacional no momento. Estou surpreso que funcione para você sem isso - não funcionou para mim até que eu o adicionei.
Zwol 15/07

1
@ user1995839 Existem códigos de controle para ocultar o cursor, mas se você fizer isso, recomendo fortemente que você o ncursesfaça.
Zwol

1
sys.stdout.flush()parece ser mendatory no meu FreebsdcomPython 2.7
Hakim

1
Observe que o retorno de carro não funciona corretamente no Python REPL (pelo menos para mim, no Ubuntu); você precisa executar um script , não apenas executar um comando REPL, para que isso funcione.
Mark Amery

50

Use print item,para fazer com que a declaração de impressão omita a nova linha.

No Python 3, é print(item, end=" ").

Se você deseja que todos os números sejam exibidos no mesmo local, use, por exemplo (Python 2.7):

to = 20
digits = len(str(to - 1))
delete = "\b" * (digits + 1)
for i in range(to):
    print "{0}{1:{2}}".format(delete, i, digits),

No Python 3, é um pouco mais complicado; aqui você precisa liberar sys.stdoutou não imprimirá nada até que o loop termine:

import sys
to = 20
digits = len(str(to - 1))
delete = "\b" * (digits)
for i in range(to):
   print("{0}{1:{2}}".format(delete, i, digits), end="")
   sys.stdout.flush()

Na verdade, parece-me que sua solução imprimirá sempre o mesmo número de backspaces. Portanto, se to for 20, imprimirá um backspace extra ao imprimir os dígitos 1..9. Você não deve calcular dígitos dentro do loop e baseá-lo no valor de i?
Adam Crossland

Justifica à direita o número e sempre exclui tudo. Não testei se é mais rápido fazer isso ou calcular em cada iteração quantos dígitos devem ser apagados agora.
Tim Pietzcker

Ou, baseie-o no valor anterior de i para contabilizar quando o número de dígitos for alterado.
Adam Crossland

Ah, sim, eu havia ignorado a justificação certa. Boa solução.
Adam Crossland

Parece bastante complicado. Eu provavelmente não entenderia o que tinha feito lá se tivesse que olhar para o meu código daqui a um ano. (Só tinha de ler um programa que eu escrevi em 2007 - eu estou tão feliz que eu escrevi em Python.)
Tim Pietzcker

16

Como os outros exemplos,
uso uma abordagem semelhante, mas em vez de gastar tempo calculando o último tamanho da saída, etc.,

Eu simplesmente uso escapes de código ANSI para retornar ao início da linha e, em seguida, limpar toda a linha antes de imprimir minha saída de status atual.

import sys

class Printer():
    """Print things to stdout on one line dynamically"""
    def __init__(self,data):
        sys.stdout.write("\r\x1b[K"+data.__str__())
        sys.stdout.flush()

Para usar em seu loop de iteração, basta chamar algo como:

x = 1
for f in fileList:
    ProcessFile(f)
    output = "File number %d completed." % x
    Printer(output)
    x += 1   

Veja mais aqui


14

Você pode adicionar uma vírgula à sua declaração de impressão para imprimir um espaço em vez de uma nova linha em cada iteração:

print item,

Como alternativa, se você estiver usando o Python 2.6 ou posterior, poderá usar a nova função de impressão, que permitiria especificar que nem mesmo um espaço chegaria ao final de cada item que está sendo impresso (ou permitir que você especifique qualquer que seja o final) quer):

from __future__ import print_function
...
print(item, end="")

Por fim, você pode gravar diretamente na saída padrão importando-a do módulo sys, que retorna um objeto semelhante a um arquivo:

from sys import stdout
...
stdout.write( str(item) )

13

mudança

print item

para

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" limpa até o final da linha
  • the \ r, retorna ao início da linha
  • a instrução flush garante que apareça imediatamente para que você obtenha a saída em tempo real.

Isso é ótimo para o Python 2.7. Você pode fornecer uma referência para onde você aprendeu sobre o \033[Kcódigo? Eu gostaria de aprender mais sobre eles.
Klik 16/10

printjá libera internamente. Não há necessidade de chamá-lo. printé diferente de sys.stdout.write()onde você precisa liberar a tela
Gabriel Fair

5

Eu acho que uma junção simples deve funcionar:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)

4
A compreensão iria ler melhor e, provavelmente, ser mais rápido: print ' '.join(str(x) for x in range(1, 10)).
Mu mente

Em segundo lugar, uso de uma lista de compreensão. Nesse caso, facilitaria a leitura uniforme.
Austin Henley

5

Outra resposta que estou usando no 2.7, onde estou apenas imprimindo um "." toda vez que um loop é executado (para indicar ao usuário que as coisas ainda estão em execução) é o seguinte:

print "\b.",

Imprime o "." caracteres sem espaços entre cada um. Parece um pouco melhor e funciona muito bem. O \ b é um caractere de backspace para quem está se perguntando.


4

Tantas respostas complicadas. Se você possui o python 3, basta colocar \rno início da impressão e adicionar end='', flush=Truea ele:

import time

for i in range(10):
    print(f'\r{i} foo bar', end='', flush=True)
    time.sleep(0.5)

Isso vai escrever 0 foo bar , então 1 foo baretc, no local.


Obrigado, isso foi exatamente o que eu precisavaprint('\r' + filename + " ", end = '', flush=True)
McPeppr

3

Para fazer com que os números se substituam, você pode fazer algo assim:

for i in range(1,100):
    print "\r",i,

Isso deve funcionar desde que o número seja impresso na primeira coluna.

EDIT: Aqui está uma versão que funcionará mesmo que não seja impressa na primeira coluna.

prev_digits = -1
for i in range(0,1000):
    print("%s%d" % ("\b"*(prev_digits + 1), i)),
    prev_digits = len(str(i))

Devo observar que esse código foi testado e funciona perfeitamente no Python 2.5 no Windows, no console do Windows. De acordo com alguns outros, a descarga do stdout pode ser necessária para ver os resultados. YMMV.


3

"A propósito ...... Como atualizá-lo toda vez para que você imprima mi em um só lugar, basta alterar o número."

É um tópico realmente complicado. O que o zack sugeriu (enviar códigos de controle do console) é uma maneira de conseguir isso.

Você pode usar (n) maldições, mas isso funciona principalmente em * nixes.

No Windows (e aqui vai a parte interessante), que raramente é mencionada (não entendo o porquê), você pode usar as ligações do Python ao WinAPI ( http://sourceforge.net/projects/pywin32/ também com o ActivePython por padrão) - não é tão difícil e funciona bem. Aqui está um pequeno exemplo:

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    output_handle.WriteConsoleOutputCharacter( i, pos )
    time.sleep( 1 )

Ou, se você deseja usar print(instrução ou função, não há diferença):

import win32console, time

output_handle = win32console.GetStdHandle(  win32console.STD_OUTPUT_HANDLE )
info = output_handle.GetConsoleScreenBufferInfo()
pos = info["CursorPosition"]

for i in "\\|/-\\|/-":
    print i
    output_handle.SetConsoleCursorPosition( pos )
    time.sleep( 1 )

win32console O módulo permite que você faça muitas coisas mais interessantes com o console do Windows ... Eu não sou um grande fã do WinAPI, mas recentemente percebi que pelo menos metade da minha antipatia por isso foi causada pela escrita do código WinAPI nas ligações Python C muito mais fácil de usar.

Todas as outras respostas são ótimas e pitônicas, é claro, mas ... E se eu quisesse imprimir na linha anterior ? Ou escreva um texto com várias linhas, depois limpe-o e escreva as mesmas linhas novamente? Minha solução torna isso possível.


2

para Python 2.7

for x in range(0, 3):
    print x,

para Python 3

for x in range(0, 3):
    print(x, end=" ")

1
In [9]: print?
Type:           builtin_function_or_method
Base Class:     <type 'builtin_function_or_method'>
String Form:    <built-in function print>
Namespace:      Python builtin
Docstring:
    print(value, ..., sep=' ', end='\n', file=sys.stdout)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file: a file-like object (stream); defaults to the current sys.stdout.
sep:  string inserted between values, default a space.
end:  string appended after the last value, default a newline.

0

Se você quiser apenas imprimir os números, pode evitar o loop.

# python 3
import time

startnumber = 1
endnumber = 100

# solution A without a for loop
start_time = time.clock()
m = map(str, range(startnumber, endnumber + 1))
print(' '.join(m))
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('took {0}ms\n'.format(timetaken))

# solution B: with a for loop
start_time = time.clock()
for i in range(startnumber, endnumber + 1):
    print(i, end=' ')
end_time = time.clock()
timetaken = (end_time - start_time) * 1000
print('\ntook {0}ms\n'.format(timetaken))

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 levou 21.1986929975ms

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 levou 491.466823551ms


Deve ser ainda mais rápido com a compreensão da lista em vez de map.
CJul

Sim bons exemplos. Eu gosto, mas preciso mostrar o resultado da análise. Primeiro conto os itens no banco de dados e imprimo quanto resta.
Pol

0

A melhor maneira de conseguir isso é usar o \rpersonagem

Apenas tente o código abaixo:

import time
for n in range(500):
  print(n, end='\r')
  time.sleep(0.01)
print()  # start new line so most recently printed number stays

0

No Python 3, você pode fazer o seguinte:

for item in range(1,10):
    print(item, end =" ")

Saídas:

1 2 3 4 5 6 7 8 9 

Tupla: você pode fazer o mesmo com uma tupla:

tup = (1,2,3,4,5)

for n in tup:
    print(n, end = " - ")

Saídas:

1 - 2 - 3 - 4 - 5 - 

Outro exemplo:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for item in list_of_tuples:
    print(item)

Saídas:

(1, 2)
('A', 'B')
(3, 4)
('Cat', 'Dog')

Você pode até descompactar sua tupla assim:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]

# Tuple unpacking so that you can deal with elements inside of the tuple individually
for (item1, item2) in list_of_tuples:
    print(item1, item2)   

Saídas:

1 2
A B
3 4
Cat Dog

outra variação:

list_of_tuples = [(1,2),('A','B'), (3,4), ('Cat', 'Dog')]
for (item1, item2) in list_of_tuples:
    print(item1)
    print(item2)
    print('\n')

Saídas:

1
2


A
B


3
4


Cat
Dog

Eu tentei todos os exemplos aqui e nenhum funciona no python 3.8. Obtenha mais respostas.
KOTZ 16/03

Eu testei com python 3.7
Stryker

O que quero dizer é que nenhuma dessas opções substitui o último número, como foi sugerido no final da pergunta.
KOTZ 20/03

0

Uma vírgula no final da instrução print omite a nova linha.

for i in xrange(1,100):
  print i,

mas isso não substitui.


0

Para aqueles que lutam como eu, criei o seguinte que parece funcionar no python 3.7.4 e 3.5.2.

Eu ampliei o intervalo de 100 para 1.000.000 porque ele roda muito rápido e você pode não ver a saída. Isso ocorre porque um efeito colateral da configuração end='\r'é que a iteração do loop final limpa toda a saída. Era necessário um número maior para demonstrar que funciona. Esse resultado pode não ser desejável em todos os casos, mas foi bom no meu, e o OP não especificou uma maneira ou de outra. Você poderia contornar isso com uma instrução if que avalia o comprimento da matriz que está sendo iterada, etc. A chave para fazê-la funcionar no meu caso era acoplar os colchetes "{}"a.format() . Caso contrário, não funcionou.

Abaixo deve funcionar como está:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)

0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Saída: 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, 25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, 50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74, 75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,92,93,94,963 utilizadores


0

Ou ainda mais simples:

import time
a = 0
while True:
    print (a, end="\r")
    a += 1
    time.sleep(0.1)

end="\r" sobrescreverá do início [0:] da primeira impressão.

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.