Печать в одну строку динамически


307

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

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

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

Результат:

1
2
3
4
.
.
.

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

1 2 3 4 5 ...

Более того, возможно ли напечатать одно число поверх последнего числа, чтобы на экране одновременно отображалось только одно число?


Ответы:


483

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

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

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

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

От http://docs.python.org/reference/simple_stmts.html#print :> Символ '\n'пишется в конце, если только printоператор не заканчивается запятой. Это единственное действие, если инструкция содержит только ключевое слово print.
ewall

5
К вашему сведению: print (item, end = "") можно использовать в Python2.7, добавив «из будущего импорта print_function» вверху файла.
Гек

2
Но flushне работает с from __future__ import print_functionк сожалению.
Тимммм

@ ну, если бы я должен был это сделать, print(item, end=", ")то также добавил ,к последнему пункту, как это сделать, чтобы предотвратить добавление ,к последнему элементу
MarcoBianchi

@SamirTendulkar Если вы используете цикл for, как в исходном вопросе, вы можете создать специальный случай, чтобы обработать последний элемент в списке по-другому ...
ewall

156

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

В общем, способ сделать это с помощью управляющих кодов терминала . Это особенно простой случай, для которого вам нужен только один специальный символ: 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с прямым использованием файловых объектов.


Что означает функция flush ()? Потому что это работает для меня без этой функции!
Пол

1
Обычно файловые объекты Python накапливают данные, поэтому они могут отправлять их в операционную систему большими порциями. Обычно это то, что вам нужно для доступа к файлам на диске, но это мешает выполнению такого рода задач. flush()заставляет файл отправлять все, что у него есть, в операционную систему прямо сейчас. Я удивлен, что это работает для вас без этого - это не работало для меня, пока я не добавил это.
Звол

1
@ user1995839 Существуют управляющие коды, чтобы скрыть курсор, но если вы собираетесь это сделать, я настоятельно рекомендую вам использовать ncursesэто.
Звол

1
sys.stdout.flush()кажется, что mendatory на мой FreebsdсPython 2.7
Hakim

1
Обратите внимание, что возврат каретки не работает должным образом в Python REPL (по крайней мере для меня, в Ubuntu); вам нужно выполнить скрипт , а не просто выполнить команду REPL, чтобы все это работало.
Марк Амери

50

Используйте, 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()

На самом деле, мне кажется, что ваше решение будет печатать одинаковое количество пробелов каждый раз. Таким образом, если значение равно 20, будет напечатано дополнительное обратное пространство во время печати цифр 1..9. Разве вы не должны вычислять цифры внутри цикла и основывать его на значении i?
Адам Кроссленд

Он выравнивает число по правому краю и всегда удаляет все. Я не проверял, быстрее ли это сделать или рассчитать на каждой итерации, сколько цифр нужно стереть прямо сейчас.
Тим Пицкер

Или, основываясь на предыдущем значении i, учтите, когда количество цифр изменится.
Адам Кроссленд

Ах, да, я упустил правильное обоснование. Хорошее решение
Адам Кроссленд

Звучит довольно сложно. Я, вероятно, не пойму, что я там делал, если бы мне пришлось смотреть на мой код через год. (Просто нужно было прочитать программу, которую я написал в 2007 году - я так рад, что написал ее на Python.)
Тим Пицкер

16

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

Я просто использую экранирование кода 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

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

print item,

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

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

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

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

13

изменение

print item

в

print "\033[K", item, "\r",
sys.stdout.flush()
  • «\ 033 [K» очищает до конца строки
  • \ r, возвращает в начало строки
  • Оператор flush обеспечивает немедленное обнаружение, чтобы вы могли получать информацию в реальном времени.

Это отлично подходит для Python 2.7. Можете ли вы дать ссылку, где вы узнали о \033[Kкоде? Я хотел бы узнать больше о них.
Клик

printуже сбрасывает внутренне. Не нужно называть это. printотличается от того, sys.stdout.write()где вы должны сбросить на экран
Gabriel Fair

5

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

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

4
Понимание будет читать лучше и, вероятно, будет быстрее print ' '.join(str(x) for x in range(1, 10)).
Му разум

Я второй использование списка понимания. В этом случае было бы легче читать даже.
Остин Хенли

5

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

print "\b.",

Он печатает "." символы без пробелов между каждым. Это выглядит немного лучше и работает довольно хорошо. \ B является символом возврата для тех, кто интересуется.


4

Так много сложных ответов. Если у вас есть Python 3, просто поместите \rв начале печати и добавьте end='', flush=Trueк нему:

import time

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

Это напишет 0 foo bar, затем и 1 foo barт. Д., На месте.


Спасибо, это было как раз то, что мне было нужноprint('\r' + filename + " ", end = '', flush=True)
McPeppr

3

Чтобы числа перезаписывали друг друга, вы можете сделать что-то вроде этого:

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

Это должно работать, пока число напечатано в первом столбце.

РЕДАКТИРОВАТЬ: Вот версия, которая будет работать, даже если она не напечатана в первом столбце.

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

Я должен отметить, что этот код был протестирован и прекрасно работает в Python 2.5 для Windows, в консоли WIndows. Согласно некоторым другим, для просмотра результатов может потребоваться очистка stdout. YMMV.


3

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

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

Вы можете использовать (n) curses, но это работает в основном на * 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 на C - пифонические привязки гораздо проще в использовании.

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



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

Если вы просто хотите напечатать числа, вы можете избежать цикла.

# 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 заняло 21,1986929975мс

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 заняло 491,466823551мс


Должно быть еще быстрее с пониманием списка вместо map.
Чи

Да, хорошие примеры. Мне это нравится, но мне нужно показать результат разбора. Сначала я считаю вещи в базе данных, а затем печатаю, сколько осталось.
Пол

0

Лучший способ сделать это - использовать \rперсонажа.

Просто попробуйте следующий код:

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

В Python 3 вы можете сделать это следующим образом:

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

Выходы:

1 2 3 4 5 6 7 8 9 

Кортеж: вы можете сделать то же самое с кортежем:

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

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

Выходы:

1 - 2 - 3 - 4 - 5 - 

Другой пример:

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

Выходы:

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

Вы даже можете распаковать ваш кортеж так:

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)   

Выходы:

1 2
A B
3 4
Cat Dog

другой вариант:

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

Выходы:

1
2


A
B


3
4


Cat
Dog

Я попробовал все примеры здесь, и ни один из них не работает в Python 3.8 Пожалуйста, получите больше ответов.
KOTZ

Я проверил это с питоном 3.7
Страйкер

Я имею в виду, что ни один из этих вариантов не перезаписывает последнее число, как это было предложено в конце вопроса.
КОТЦ

0

Запятая в конце оператора print пропускает новую строку.

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

но это не перезаписать.


0

Для тех, кто боролся, как я, я придумал следующее, которое, кажется, работает как в Python 3.7.4, так и в 3.5.2.

Я расширил диапазон со 100 до 1000000, потому что он работает очень быстро, и вы можете не увидеть результат. Это связано с тем, что одним из побочных эффектов установки end='\r'является то, что последняя итерация цикла очищает весь вывод. Более длинный номер был необходим, чтобы продемонстрировать, что это работает. Этот результат может быть нежелателен во всех случаях, но в моем случае это было нормально, и OP не указывал так или иначе. Вы могли бы потенциально обойти это с помощью оператора if, который оценивает длину итерируемого массива и т. Д. Ключом, чтобы заставить его работать в моем случае, было объединение скобок "{}"с.format() . В противном случае это не сработало.

Ниже должно работать как есть:

#!/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=',')

Выход: 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


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.