Печатать в одну строку динамически - PullRequest
270 голосов
/ 14 июля 2010

Я хотел бы сделать несколько операторов, которые дают стандартный вывод, не видя перевода строки между операторами.

В частности, предположим, что у меня есть:

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

Результат:

1
2
3
4
.
.
.

Как это выглядит вместо этого:

1 2 3 4 5 ...

Еще лучше, возможно ли напечатать одно число поверх последнего числа, поэтому на экране одновременно отображается только одно число?

Ответы [ 17 ]

437 голосов
/ 14 июля 2010

Измените print item на:

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

Если вы хотите напечататьданные динамически используют следующий синтаксис:

  • print(item, sep=' ', end='', flush=True) в Python 3
144 голосов
/ 14 июля 2010

Кстати ...... Как обновлять его каждый раз, чтобы печатать ми в одном месте, просто измените номер.

Обычно это можно сделать с помощью кодов управления клеммами . Это особенно простой случай, для которого вам нужен только один специальный символ: U + 000D ВОЗВРАТ ЗАРЯДА, который написан '\r' на Python (и многих других языках). Вот полный пример, основанный на вашем коде:

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

Некоторые вещи об этом, которые могут быть удивительными:

  • \r идет в начале строки, так что во время работы программы курсор всегда будет после числа. Это не просто косметика: некоторые эмуляторы терминала очень запутываются, если вы делаете это наоборот.
  • Если вы не включите последнюю строку, то после завершения программы ваша оболочка напечатает подсказку поверх числа.
  • stdout.flush необходим в некоторых системах, иначе вы не получите никакого вывода. Другие системы могут не требовать этого, но это не приносит никакого вреда.

Если вы обнаружите, что это не работает, первое, о чем вы должны подозревать, это то, что ваш эмулятор терминала содержит ошибки. Программа vttest может помочь вам проверить это.

Вы можете заменить stdout.write на оператор print, но я предпочитаю не смешивать print с прямым использованием файловых объектов.

48 голосов
/ 14 июля 2010

Используйте print item,, чтобы оператор печати опускал символ новой строки.

В Python 3 это print(item, end=" ").

Если вы хотите, чтобы каждое число отображалось в одном и том же месте, используйте, например, (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),

В Python 3 все немного сложнее; здесь вам нужно сбросить sys.stdout, иначе ничего не будет напечатано, пока цикл не закончится:

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()
16 голосов
/ 15 июня 2011

Как и другие примеры,
Я использую аналогичный подход, но вместо того, чтобы тратить время на вычисление последней длины вывода и т. Д.,

Я просто использую экранирование кода ANSI, чтобы вернуться к началу строки, а затем очистить всю строку перед выводом текущего состояния.

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

Чтобы использовать в своем цикле итерации, вы бы просто вызвали что-то вроде:

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

Подробнее здесь

14 голосов
/ 14 июля 2010

Вы можете добавить запятую в свой оператор печати для печати пробела вместо новой строки в каждой итерации:

print item,

В качестве альтернативы, если вы используете Python 2.6 или более позднюю версию, вы можете использоватьновая функция печати, которая позволит вам указать, что даже в конце каждого печатаемого элемента не должно быть пробела (или указать любой желаемый конец):

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

Наконец, вы можетезаписывать напрямую в стандартный вывод, импортируя его из модуля sys, который возвращает файлоподобный объект:

from sys import stdout
...
stdout.write( str(item) )
10 голосов
/ 15 июля 2015

изменить

print item

на

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" очищает до конца строки
  • \ r, возвращаетдо начала строки
  • оператор flush обеспечивает немедленное его обнаружение, поэтому вы получаете вывод в реальном времени.
5 голосов
/ 20 сентября 2012

Я думаю, что простое объединение должно работать:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)
4 голосов
/ 14 января 2016

Другой ответ, который я использую на 2.7, где я просто распечатываю "."каждый раз, когда цикл запускается (чтобы указать пользователю, что все еще работает), это:символы без пробелов между каждым.Это выглядит немного лучше и работает довольно хорошо.\ B является символом возврата для тех, кто интересуется.

3 голосов
/ 15 июля 2010

"Кстати ...... Как обновлять его каждый раз, чтобы печатать ми в одном месте, просто измените номер."

Это действительно сложная тема. То, что zack предлагает (вывод управляющих кодов консоли), является одним из способов достижения этого.

Вы можете использовать (n) проклятий, но это работает в основном на * nixes.

В Windows (и здесь идет интересная часть), которая редко упоминается (я не могу понять почему), вы можете использовать привязки Python к WinAPI (http://sourceforge.net/projects/pywin32/ также с ActivePython по умолчанию) - это не так сложно и работает хорошо. Вот небольшой пример:

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 )

Или, если вы хотите использовать print (оператор или функция, без разницы):

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 модуль позволяет вам делать намного больше интересных вещей с консолью Windows ... Я не большой поклонник WinAPI, но недавно я понял, что, по крайней мере, половина моей антипатии к этому была вызвана написанием кода WinAPI в С - пифонические привязки намного проще в использовании.

Все остальные ответы, конечно, великолепны и питонны, но ... Что если я захочу напечатать в предыдущую строку? Или написать многострочный текст, чем очистить его и снова написать те же строки? Мое решение делает это возможным.

2 голосов
/ 17 декабря 2015

для Python 2.7

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

для Python 3

for x in range(0, 3):
    print(x, end=" ")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...