Друкуйте в одному рядку динамічно


306

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

Припустимо, маю:

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

Результат:

1
2
3
4
.
.
.

Як це зробити замість цього:

1 2 3 4 5 ...

Ще краще, чи можна надрукувати єдине число над останнім номером, тож одночасно на екрані відображається лише одне число?


Відповіді:


482

Змінити 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
FYI: print (item, end = "") можна використовувати в Python2.7, додавши "з майбутнього імпорту print_function" вгорі файлу.
Гек

2
Але flushне працює, на from __future__ import print_functionжаль.
Тимммм

@ewall, якщо я маю print(item, end=", ")це зробити, то також додає ,до останнього пункту, як зробити це, щоб запобігти його доданню ,до останнього пункту
MarcoBianchi

@SamirTendulkar Якщо ви використовуєте for-цикл, як оригінальне запитання, ви можете зробити спеціальний випадок, щоб обробити останній елемент у списку інакше ...
ewall

156

До речі ...... Як оновити її кожен раз, щоб надрукувати mi в одному місці просто змінити номер.

Загалом, спосіб цього зробити термінальними кодами управління . Це особливо простий випадок, для якого вам потрібен лише один спеціальний символ: 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

Про це можуть бути дивні речі:

  • The \rЙде на початку рядка , так що, в той час як програма працює, курсор завжди буде після номера. Це не просто косметично: деякі термінальні емулятори сильно плутаються, якщо робити це навпаки.
  • Якщо ви не включите останній рядок, після закінчення програми ваша оболонка надрукує своє запит зверху на номер.
  • Це stdout.flushнеобхідно в деяких системах, інакше ви не отримаєте жодного результату. Інші системи можуть цього не вимагати, але це не шкодить.

Якщо ви виявите, що це не працює, перше, що вам слід запідозрити, - це те, що ваш емулятор термінала баггі. Програма vttest може допомогти вам протестувати її.

Ви могли б замінити stdout.writeз printтвердженням , але я вважаю за краще не змішувати printз прямим використанням файлових об'єктів.


Яка функція meen flush ()? Тому що це працює для мене без цієї функції!
Пол

1
Зазвичай файлові об’єкти Python накопичують дані, щоб вони могли надсилати їх в операційну систему великими шматками. Це те, що ви хочете, щоб отримати доступ до файлів на диску, але це заважає подібним завданням. flush()змушує файл зараз надсилати все, що є, в операційну систему. Я здивований, що це працює для вас без цього - це не спрацювало для мене, поки я не додав його.
zwol

1
@ user1995839 Існують контрольні коди, щоб приховати курсор, але якщо ви збираєтесь це зробити, я настійно рекомендую використовувати ncursesдля цього.
zwol

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, повертається до початку рядка
  • оператор флеш гарантує, що він відображається негайно, так що ви отримуєте вихід у реальному часі.

Це чудово підходить для Python 2.7. Чи можете ви надати посилання на те, де ви дізналися про \033[Kкод? Я хотів би дізнатися більше про них.
Клік

printвже внутрішньо спалахує. Не потрібно це називати. printвідрізняється від місця, sys.stdout.write()де вам потрібно вийти на екран
Габріель Ярмарок

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)).
Mu Mind

Я друге використання розуміння списку. У цьому випадку було б простіше читати навіть.
Остін Генлі

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,

Це повинно працювати до тих пір, поки число надрукується в першій колонці.

EDIT: Ось версія, яка працює, навіть якщо вона не надрукована в першому стовпці.

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. За твердженнями деяких інших, для перегляду результатів може знадобитися промивання штриху. YMMV.


3

"До речі ...... Як оновити її кожен раз, щоб надрукувати mi в одному місці просто змінити номер."

Це дійсно хитра тема. Що зак запропонував (виведення коду управління консолями) - один із способів цього досягти.

Ви можете використовувати (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 в 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,466823551ms


Потрібно бути ще швидшим із розумінням списку замість map.
cji

Так, хороші приклади. Мені це подобається, але мені потрібно показати результат розбору. Спочатку я підраховую елементи бази даних, ніж друкую, скільки залишилося.
Пол

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

Я перевірив його на python 3.7
Stryker

Я маю на увазі, що жоден із цих варіантів не замінює останнє число, як було запропоновано в кінці запитання.
KOTZ

0

Кома в кінці заяви про друк опускає новий рядок.

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

але це не перезаписується.


0

Для тих, хто бореться, як і я, я придумав таке, що, здається, працює і в пітоні 3.7.4 та 3.5.2.

Я розширив діапазон від 100 до 1 000 000, тому що він працює дуже швидко, і ви можете не побачити вихід. Це пов’язано з тим, що одним із побічних ефектів налаштування end='\r'є те, що остаточна ітерація циклу очищає весь результат. Більше число було потрібно, щоб продемонструвати, що це працює. Цей результат може виявитися небажаним не у всіх випадках, але в мене добре, і в ОП не було вказано так чи інакше. Ви можете потенційно обійти це за допомогою заяви 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.