Imprima en una línea dinámicamente

307

Me gustaría hacer varias declaraciones que den salida estándar sin ver nuevas líneas entre las declaraciones.

Específicamente, supongamos que tengo:

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

El resultado es:

1
2
3
4
.
.
.

Cómo hacer que esto se vea así:

1 2 3 4 5 ...

Aún mejor, ¿es posible imprimir el número único sobre el último número, por lo que solo hay un número en la pantalla a la vez?

Pol
fuente
Publicación relacionada: ¿Cómo imprimir sin nueva línea o espacio?
RBT

Respuestas:

483

Cambiar print itema:

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

Si desea imprimir los datos dinámicamente, use la siguiente sintaxis:

  • print(item, sep=' ', end='', flush=True) en Python 3
ewall
fuente
De http://docs.python.org/reference/simple_stmts.html#print :> Se '\n'escribe un carácter al final, a menos que la printdeclaración termine con una coma. Esta es la única acción si la declaración contiene solo la palabra clave print.
ewall
55
FYI: print (item, end = "") se puede usar en Python2.7 agregando 'from future import print_function' en la parte superior del archivo.
Hec
2
Pero desafortunadamente flushno funciona from __future__ import print_function.
Timmmm
@ewall si tuviera que hacerlo print(item, end=", "), entonces también agrega ,al último elemento cómo evitar que se agregue ,al último elemento
MarcoBianchi
@SamirTendulkar Si está utilizando un bucle for como la pregunta original, usted podría hacer un caso especial para manejar el último elemento de la lista de otra manera ...
ewall
156

Por cierto ...... Cómo actualizarlo cada vez para que imprima mi en un solo lugar simplemente cambie el número.

En general, la forma de hacerlo es con códigos de control de terminal . Este es un caso particularmente simple, para el que solo necesita un carácter especial: U + 000D CARRIAGE RETURN, que está escrito '\r'en Python (y en muchos otros idiomas). Aquí hay un ejemplo completo basado en su 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

Algunas cosas sobre esto que pueden ser sorprendentes:

  • El \rva al principio de la cadena de manera que, mientras que el programa se está ejecutando, el cursor siempre será después del número. Esto no es solo cosmético: algunos emuladores de terminal se confunden mucho si lo hace al revés.
  • Si no incluye la última línea, luego de que el programa finalice, su shell imprimirá su mensaje en la parte superior del número.
  • El stdout.flushes necesaria en algunos sistemas, o no se va a ninguna salida. Otros sistemas pueden no requerirlo, pero no hace ningún daño.

Si encuentra que esto no funciona, lo primero que debe sospechar es que su emulador de terminal tiene errores. El mejor programa puede ayudarlo a probarlo.

Puede reemplazar el stdout.writecon una printdeclaración, pero prefiero no mezclarlo printcon el uso directo de objetos de archivo.

zwol
fuente
¿Qué función meen flush ()? ¡Porque funciona para mí sin esa función!
Pol
1
Normalmente, los objetos de archivo de Python acumulan datos para que puedan enviarlos al sistema operativo en grandes fragmentos. Esto es lo que desea para acceder a los archivos en el disco, por lo general, pero interfiere con este tipo de tarea. flush()obliga a un archivo a enviar lo que sea que tenga al sistema operativo en este momento. Me sorprende que funcione para ti sin eso, no funcionó para mí hasta que lo agregué.
zwol
1
@ user1995839 Hay códigos de control para ocultar el cursor, pero si vas a hacerlo, te recomiendo que lo uses ncurses.
zwol
1
sys.stdout.flush()parece ser obligatorio en mi FreebsdconPython 2.7
Hakim
1
Tenga en cuenta que el retorno de carro no funciona correctamente dentro de Python REPL (al menos para mí, en Ubuntu); debe ejecutar un script , no solo ejecutar un comando REPL, para que todo esto funcione.
Mark Amery
50

Use print item,para hacer que la declaración de impresión omita la nueva línea.

En Python 3, es print(item, end=" ").

Si desea que cada número se muestre en el mismo lugar, use por ejemplo (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),

En Python 3, es un poco más complicado; aquí necesita enjuagar sys.stdouto no imprimirá nada hasta que el ciclo haya terminado:

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()
Tim Pietzcker
fuente
En realidad, me parece que su solución imprimirá la misma cantidad de espacios de retroceso cada vez. Entonces, si a es 20, imprimirá un retroceso adicional mientras imprime los dígitos 1..9. ¿No deberías calcular los dígitos dentro del bucle y basarlo en el valor de i?
Adam Crossland
Justifica a la derecha el número y siempre elimina todo. No he probado si es más rápido hacer eso o calcular en cada iteración cuántos dígitos hay que borrar en este momento.
Tim Pietzcker
O bien, basarlo en el valor anterior de i para tener en cuenta cuándo cambia el número de dígitos.
Adam Crossland
Ah, sí, había pasado por alto la justificación correcta. Buena solución.
Adam Crossland
Suena bastante complicado. Probablemente no entendería lo que había hecho allí si tuviera que mirar mi código dentro de un año. (Solo tenía que leer un programa que escribí en 2007, estoy muy contento de haberlo escrito en Python)
Tim Pietzcker,
16

Al igual que los otros ejemplos,
utilizo un enfoque similar, pero en lugar de perder tiempo calculando la última longitud de salida, etc.

Simplemente uso los escapes de código ANSI para volver al principio de la línea y luego borrar esa línea completa antes de imprimir mi salida de estado actual.

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 en su ciclo de iteración simplemente llamaría algo como:

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

Ver más aquí

Mateo
fuente
14

Puede agregar una coma final a su declaración de impresión para imprimir un espacio en lugar de una nueva línea en cada iteración:

print item,

Alternativamente, si está usando Python 2.6 o posterior, puede usar la nueva función de impresión, que le permitiría especificar que ni siquiera debería aparecer un espacio al final de cada elemento que se está imprimiendo (o le permitirá especificar el final que desee). querer):

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

Finalmente, puede escribir directamente en la salida estándar importándola desde el módulo sys, que devuelve un objeto similar a un archivo:

from sys import stdout
...
stdout.write( str(item) )
Eli Courtwright
fuente
13

cambio

print item

a

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" se borra hasta el final de la línea
  • el \ r, vuelve al comienzo de la línea
  • la instrucción flush se asegura de que se muestre de inmediato para que obtenga resultados en tiempo real.
Arroyos
fuente
Esto es genial para Python 2.7. ¿Puede proporcionar una referencia de dónde aprendió sobre el \033[Kcódigo? Me gustaría aprender más sobre ellos.
Klik
printYa se sonroja internamente. No hay necesidad de llamarlo. printes diferente de sys.stdout.write()donde tienes que descargar la pantalla
Gabriel Fair
5

Creo que una combinación simple debería funcionar:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)
xortion
fuente
44
Una comprensión mejor sería leer y probablemente sea más rápido: print ' '.join(str(x) for x in range(1, 10)).
Mu Mind
Secundo el uso de una lista de comprensión. En este caso, sería más fácil de leer incluso.
Austin Henley
5

Otra respuesta que estoy usando en 2.7 donde solo estoy imprimiendo un "." cada vez que se ejecuta un bucle (para indicar al usuario que las cosas aún se están ejecutando) es esto:

print "\b.",

Imprime el "." personajes sin espacios entre cada uno. Se ve un poco mejor y funciona bastante bien. El \ b es un carácter de retroceso para aquellos que se preguntan.

copeland3300
fuente
4

Tantas respuestas complicadas. Si tiene Python 3, simplemente colóquelo \ral comienzo de la impresión y agréguelo end='', flush=True:

import time

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

Esto escribirá 0 foo bar, luego 1 foo bar, etc., en el lugar.

Hugh Perkins
fuente
Gracias, eso era justo lo que necesitabaprint('\r' + filename + " ", end = '', flush=True)
McPeppr
3

Para que los números se sobrescriban entre sí, puede hacer algo como esto:

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

Eso debería funcionar siempre que el número se imprima en la primera columna.

EDITAR: Aquí hay una versión que funcionará incluso si no está impresa en la primera columna.

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

Debo señalar que este código fue probado y funciona bien en Python 2.5 en Windows, en la consola de Windows. Según algunos otros, puede ser necesario el enjuague de stdout para ver los resultados. YMMV.

Adam Crossland
fuente
3

"Por cierto ...... Cómo actualizarlo cada vez para que imprima mi en un solo lugar simplemente cambie el número".

Es un tema realmente complicado. Lo que sugirió zack (generar códigos de control de consola) es una forma de lograrlo.

Puede usar (n) maldiciones, pero eso funciona principalmente en * nixes.

En Windows (y aquí va la parte interesante) que rara vez se menciona (no entiendo por qué) puede usar enlaces de Python a WinAPI ( http://sourceforge.net/projects/pywin32/ también con ActivePython de forma predeterminada) - no así de duro y funciona bien. Aquí hay un pequeño ejemplo:

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 )

O, si desea usar print(declaración o función, no hay diferencia):

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 El módulo le permite hacer muchas cosas más interesantes con la consola de Windows ... No soy un gran admirador de WinAPI, pero recientemente me di cuenta de que al menos la mitad de mi antipatía hacia él fue causada por escribir código WinAPI en C - los enlaces pitónicos son Mucho más fácil de usar.

Todas las demás respuestas son geniales y pitónicas, por supuesto, pero ... ¿Y si quisiera imprimir en la línea anterior ? ¿O escribir texto multilínea, que borrarlo y volver a escribir las mismas líneas? Mi solución lo hace posible.

cji
fuente
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=" ")
Adnan Ghaffar
fuente
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.
gtrak
fuente
0

Si solo desea imprimir los números, puede evitar el bucle.

# 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 99100 tomó 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 99100 tomó 491.466823551 ms

Mahmoud Kassem
fuente
Debería ser aún más rápido con la comprensión de la lista en lugar de map.
cji
Si buenos ejemplos. Me gusta, pero necesito mostrar el resultado del análisis. Primero cuento los elementos en la base de datos que imprimo cuánto queda.
Pol
0

La mejor manera de lograr esto es usar el \rpersonaje

Solo prueba el siguiente código:

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
vitiral
fuente
0

En Python 3 puedes hacerlo de esta manera:

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

Salidas:

1 2 3 4 5 6 7 8 9 

Tupla: Puedes hacer lo mismo con una tupla:

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

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

Salidas:

1 - 2 - 3 - 4 - 5 - 

Otro ejemplo:

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

Salidas:

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

Incluso puedes desempacar tu tupla así:

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)   

Salidas:

1 2
A B
3 4
Cat Dog

otra variante:

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

Salidas:

1
2


A
B


3
4


Cat
Dog
Stryker
fuente
He probado todos los ejemplos aquí y ninguno funciona en Python 3.8. Obtenga más respuestas.
KOTZ
Lo he probado con python 3.7
Stryker
Lo que quiero decir es que ninguna de estas opciones sobrescribe el último número como se sugirió al final de la pregunta.
KOTZ
0

Una coma al final de la declaración de impresión omite la nueva línea.

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

pero esto no sobrescribe.

eruciforme
fuente
0

Para aquellos que luchaban como lo hice, se me ocurrió lo siguiente que parece funcionar tanto en Python 3.7.4 como en 3.5.2.

Amplié el rango de 100 a 1,000,000 porque se ejecuta muy rápido y es posible que no vea la salida. Esto se debe a que un efecto secundario de la configuración end='\r'es que la iteración del bucle final borra toda la salida. Se necesitaba un número más largo para demostrar que funciona. Este resultado puede no ser deseable en todos los casos, pero estuvo bien en el mío, y OP no especificó de una manera u otra. Usted podría eludir esto con una sentencia if que evalúa la longitud del ser gama repiten a lo largo, etc. La clave para conseguir que funcione en mi caso era para acoplar los soportes "{}"con .format(). De lo contrario, no funcionó.

A continuación debería funcionar como está:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)
Estructura
fuente
0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Salida: 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

Alex
fuente
0

O incluso más simple:

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

end="\r" sobrescribirá desde el principio [0:] de la primera impresión.

Evan Schwartzentruber
fuente