Imprima en la misma línea y no en una nueva línea en Python


85

Básicamente quiero hacer lo contrario de lo que hizo este tipo ... jeje.

Python Script: imprima una nueva línea cada vez en el shell en lugar de actualizar la línea existente

Tengo un programa que me dice qué tan avanzado está.

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

Entonces, si len (some_list) tuviera 50, obtendría esa última línea impresa 50 veces. Quiero imprimir una línea y seguir actualizando esa línea. Sé que sé que esta es probablemente la pregunta más tonta que leerá en todo el día. Simplemente no puedo entender las cuatro palabras que necesito poner en Google para obtener la respuesta.

¡Actualizar! Probé la sugerencia de mvds que PARECÍA correcta. El nuevo código

print percent_complete,"           \r",

El porcentaje completo es solo una cadena (estaba abstrayendo la primera vez que ahora intento ser literal). El resultado ahora es que ejecuta el programa, no imprime NADA hasta que finaliza el programa y luego imprime "100 por ciento completo" en una y sólo una línea.

Sin el retorno de carro (pero con la coma, la mitad de la sugerencia de mvds) no imprime nada hasta el final. Y luego imprime:

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

Y así. Así que ahora el nuevo problema es que con la coma no se imprime hasta que finaliza el programa.

Con el retorno de carro y sin coma se comporta exactamente igual que con ninguno.


Es posible que también desee verificar sys.stdout.isatty()para no escupir estas cosas cuando no se esté ejecutando en una terminal.
mvds

Estoy ejecutando esto desde una terminal ... aunque está bien pensado. Estoy seguro de que lo necesitaré en algún momento.
chriscauley

1
el trasfondo es, por cierto, que en varios idiomas el \ n (que ahora omitimos) sirve como una señal implícita para vaciar a stdout. De lo contrario, mucha gente estará confundida.
mvds

Respuestas:


85

Se llama retorno de carro, o \r

Utilizar

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

La coma evita que la impresión agregue una nueva línea. (y los espacios mantendrán la línea despejada de la salida anterior)

Además, ¡no olvide terminar con un print ""para obtener al menos una nueva línea de finalización!


12
Solo asegúrese de imprimir siempre la misma cantidad de datos (o más que cualquier impresión anterior) en la línea, de lo contrario, terminará con cruft al final.
Nicholas Knight

Tan cerca ... Actualizaré la pregunta con el resultado de esto.
chriscauley

2
@dustynachos: Je, me olvidé de esa arruga. Consulte la pregunta sobre el búfer de salida de Python: stackoverflow.com/questions/107705/python-output-buffering
Nicholas Knight

1
@dustynachos: (o simplemente use sys.stdout.flush () después de cada llamada de impresión, eso puede ser mejor si no le importa el almacenamiento en búfer de salida para el resto de su programa)
Nicholas Knight

2
esto no funciona para mí. De hecho, lo he intentado varias veces y nunca me ha funcionado. Estoy usando iterm2 en una mac, pero la mayor parte del tiempo estoy conectado a un servidor Linux. Nunca encontré un método para hacer esto que realmente funcione.
bgenchel

35

Para mí, lo que funcionó fue una combinación de las respuestas de Remi y Siriusd:

from __future__ import print_function
import sys

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

33

Desde python 3.x puedes hacer:

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

(que también se puede usar en Python 2.6 o 2.7 colocándolo from __future__ import print_functionen la parte superior de su script / módulo)

Ejemplo de barra de progreso de la consola de 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)

La \ r parece agregar una nueva línea también
fccoelho

2
esto elimina la nueva línea, pero no permite la sobrescritura, que creo que es lo que quiere el autor.
bgenchel

1
@bgenchel usado con '\ r' (como en el ejemplo de código) hace exactamente lo que OP quiere
Milo Wielondek

19

En Python 3.3+ no necesitas sys.stdout.flush(). print(string, end='', flush=True)trabajos.

Entonces

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

sobrescribirá 'foo' con 'bar'.


2
Funciona, siempre que el texto impreso termine en "\r".
bli

13

para la consola probablemente necesitará

sys.stdout.flush()

para forzar la actualización. Creo que usarlo ,en la impresión evitará que stdout se descargue y de alguna manera no se actualizará


Terminator solo actualizaba la línea cada 30 segundos cuando usaba print ("...", end = '\ r') para mí, a menos que ejecutara este comando inmediatamente después de la declaración de impresión. Gracias
Bryce Guinta

4

Tarde en el juego, pero como ninguna de las respuestas funcionó para mí (no las probé todas) y encontré esta respuesta más de una vez en mi búsqueda ... En Python 3, esta solución es bastante elegante y creo que hace exactamente lo que el autor está buscando, actualiza una sola declaración en la misma línea. Tenga en cuenta que es posible que deba hacer algo especial si la línea se encoge en lugar de crecer (como quizás hacer que la cadena tenga una longitud fija con espacios acolchados al final)

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

opción más simple y limpia para python => 3.6
DaveR

3

Esto funciona para mí, lo pirateé una vez para ver si es posible, pero nunca lo usé en mi programa (la GUI es mucho mejor):

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)

\bmoverá la ubicación del cursor hacia atrás un espacio
Así que lo movemos hacia atrás hasta el principio de la línea
Luego escribimos espacios para borrar la línea actual - a medida que escribimos espacios, el cursor se mueve hacia adelante / derecha en uno
Entonces tenemos para mover el cursor al principio de la línea antes de escribir nuestros nuevos datos

Probado en Windows cmd usando Python 2.7


1

Pruébelo así:

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

(Con una coma al final).


Esto simplemente agrega el nuevo texto al antiguo (funcionalmente similar pero feo).
chriscauley

1

Si está utilizando Spyder, las líneas simplemente se imprimen continuamente con todas las soluciones anteriores. Una forma de evitar eso es usar:

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

Esta fue la única solución que funcionaba para mí (Python 3.8, Windows, PyCharm).
z33k

0

Basado en la respuesta de Remi para Python 2.7+usar esto:

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+y para cualquiera en listlugar de solo ints, además de usar todo el ancho de la ventana de su consola y no cruzar a una nueva línea, puede usar lo siguiente:

nota: tenga en cuenta que la función get_console_with()solo funcionará en sistemas basados ​​en Linux y, como tal, debe volver a escribirla para que funcione en 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

Si está utilizando Python 3, esto es para usted y realmente funciona.

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

0

Para Python 3+

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

0

Solo descubrí esto por mi cuenta para mostrar una cuenta regresiva, pero también funcionaría para un porcentaje.

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

Siempre que lo que venga después de '/ r' tenga la misma longitud o más largo (incluidos los espacios) que la cadena anterior, lo sobrescribirá en la misma línea. Solo asegúrese de incluir end = '' de lo contrario se imprimirá en una nueva línea. ¡Espero que ayude!


0

para el objeto "pega" que proporciona StartRunning (), StopRunning (), getIsRunning () booleano y getProgress100 () entero que devuelve un valor en el rango de 0 a 100, esto proporciona una barra de progreso de texto mientras se ejecuta ...

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)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.