Drukuj w jednej linii dynamicznie

306

Chciałbym zrobić kilka instrukcji, które dają standardowe dane wyjściowe bez zauważania nowych linii pomiędzy instrukcjami.

Załóżmy, że mam:

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

Wynik to:

1
2
3
4
.
.
.

Jak to wyglądać zamiast tego:

1 2 3 4 5 ...

Co więcej, czy można wydrukować pojedynczy numer na ostatnim numerze, aby na ekranie wyświetlała się tylko jedna liczba?

Pol
źródło

Odpowiedzi:

482

Zmień print itemna:

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

Jeśli chcesz wydrukować dane dynamicznie, użyj następującej składni:

  • print(item, sep=' ', end='', flush=True) w Python 3
ewall
źródło
From http://docs.python.org/reference/simple_stmts.html#print :> '\n'Znak jest pisany na końcu, chyba że printinstrukcja kończy się przecinkiem. Jest to jedyne działanie, jeśli instrukcja zawiera tylko słowo kluczowe print.
ewall
5
FYI: print (item, end = "") może być używany w Python2.7 przez dodanie „z przyszłego importu print_function” na górze pliku.
Hec
2
Ale niestety flushnie działa from __future__ import print_function.
Timmmm
@ewall, gdybym to zrobił print(item, end=", "), dodaje również ,do ostatniego elementu, jak to zrobić, aby zapobiec dodawaniu ,go do ostatniego elementu
MarcoBianchi,
@SamirTendulkar Jeśli używasz pętli for jak w pierwotnym pytaniu, możesz zrobić specjalny przypadek, aby inaczej
potraktować
156

Przy okazji ...... Jak go odświeżyć za każdym razem, aby wydrukować mi w jednym miejscu, wystarczy zmienić numer.

Ogólnie rzecz biorąc, można to zrobić za pomocą kodów kontrolnych terminala . Jest to szczególnie prosty przypadek, dla którego potrzebujesz tylko jednego znaku specjalnego: U + 000D CARRIAGE RETURN, napisanego '\r'w Pythonie (i wielu innych językach). Oto kompletny przykład oparty na kodzie:

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

Niektóre rzeczy na ten temat mogą być zaskakujące:

  • \rIdzie na początku łańcucha tak, że podczas gdy program jest uruchomiony, kursor zawsze będzie po numerze. To nie tylko kosmetyczne: niektóre emulatory terminali bardzo się zdezorientują, jeśli zrobisz to na odwrót.
  • Jeśli nie podasz ostatniego wiersza, to po zakończeniu programu twoja powłoka wydrukuje swój monit nad liczbą.
  • Jest stdout.flushto konieczne w niektórych systemach, w przeciwnym razie nie uzyskasz żadnych danych wyjściowych. Inne systemy mogą tego nie wymagać, ale nie wyrządza to żadnej szkody.

Jeśli okaże się, że to nie działa, pierwszą rzeczą, którą powinieneś podejrzewać, jest to, że emulator terminala jest wadliwy. Vttest program może pomóc go przetestować.

Można wymienić stdout.writew printsprawozdaniu, a ja wolę nie mieszać printz bezpośredniego użytkowania obiektów plików.

zwol
źródło
Jaka funkcja meen flush ()? Ponieważ to działa dla mnie bez tej funkcji!
Pol
1
Zwykle obiekty plików Pythona gromadzą dane, aby można je było przesyłać do systemu operacyjnego w dużych porcjach. To jest zwykle to, co chcesz uzyskać dostęp do plików na dysku, ale przeszkadza to w tego rodzaju zadaniu. flush()zmusza plik do wysłania wszystkiego, co ma teraz do systemu operacyjnego. Jestem zaskoczony, że bez ciebie to działa - nie działało dla mnie, dopóki go nie dodałem.
zwol
1
@ user1995839 Istnieją kody kontrolne do ukrycia kursora, ale jeśli masz zamiar to zrobić, zdecydowanie zalecamy skorzystanie ncursesz niego.
zwolnienie
1
sys.stdout.flush()wydaje się być mendatory na moje FreebsdzPython 2.7
Hakim
1
Zauważ, że powrót karetki nie działa poprawnie w Pythonie REPL (przynajmniej dla mnie, w Ubuntu); musisz wykonać skrypt , a nie tylko komendę REPL, aby wszystko działało.
Mark Amery
50

Służy print item,do tego, aby instrukcja print pomijała nowy wiersz.

W Pythonie 3 jest to print(item, end=" ").

Jeśli chcesz, aby każda liczba wyświetlała się w tym samym miejscu, użyj na przykład (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),

W Pythonie 3 jest to trochę bardziej skomplikowane; tutaj musisz spłukać, sys.stdoutinaczej nic nie wydrukuje, dopóki pętla się nie skończy:

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
źródło
Właściwie wydaje mi się, że twoje rozwiązanie będzie drukować tę samą liczbę backspace za każdym razem. Tak więc, jeśli to jest 20, wydrukuje dodatkowy backspace podczas drukowania cyfr 1..9. Czy nie powinieneś obliczyć cyfr w pętli i oprzeć ją na wartości i?
Adam Crossland
To uzasadnia liczbę i zawsze usuwa wszystko. Nie testowałem, czy można to zrobić szybciej lub obliczyć w każdej iteracji, ile cyfr ma teraz zostać wymazanych.
Tim Pietzcker
Lub oprzyj ją na poprzedniej wartości i, aby uwzględnić, gdy zmienia się liczba cyfr.
Adam Crossland
Ach, tak, przesadziłem z uzasadnieniem. Dobre rozwiązanie.
Adam Crossland
Brzmi dość skomplikowanie. Prawdopodobnie nie zrozumiałbym, co tam zrobiłem, gdybym musiał spojrzeć na kod za rok. (Po prostu czytać program, który napisałem w 2007 roku - jestem tak zadowolony, że napisał go w Pythonie.)
Tim Pietzcker
16

Podobnie jak inne przykłady,
używam podobnego podejścia, ale zamiast spędzać czas na obliczaniu ostatniej długości wyjściowej itp.

Po prostu używam znaków ucieczki kodu ANSI, aby przejść z powrotem na początek linii, a następnie wyczyścić całą linię przed wydrukowaniem mojego aktualnego stanu wyjściowego.

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

Aby użyć w pętli iteracji, wystarczy wywołać coś takiego:

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

Zobacz więcej tutaj

Mateusz
źródło
14

Możesz dodać przecinek końcowy do instrukcji print, aby wydrukować spację zamiast nowego wiersza w każdej iteracji:

print item,

Alternatywnie, jeśli używasz języka Python 2.6 lub nowszego, możesz użyć nowej funkcji drukowania, która pozwoliłaby ci określić, że na końcu każdego drukowanego elementu nie powinna znajdować się spacja (lub pozwolić ci określić dowolny koniec chcieć):

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

Na koniec możesz pisać bezpośrednio na standardowe wyjście, importując je z modułu sys, który zwraca obiekt podobny do pliku:

from sys import stdout
...
stdout.write( str(item) )
Eli Courtwright
źródło
13

zmiana

print item

do

print "\033[K", item, "\r",
sys.stdout.flush()
  • „\ 033 [K” usuwa się do końca linii
  • \ r, wraca na początek linii
  • Instrukcja flush gwarantuje, że pojawi się natychmiast, dzięki czemu uzyskasz wyjście w czasie rzeczywistym.
Strumyki
źródło
Jest to świetne dla Python 2.7. Czy możesz podać odniesienie do tego, gdzie dowiedziałeś się o \033[Kkodzie? Chciałbym dowiedzieć się o nich więcej.
Klik
printjuż spłukuje wewnętrznie. Nie trzeba tego nazywać. printróżni się od sys.stdout.write()miejsca, w którym musisz spłukiwać ekran
Gabriel Fair
5

Myślę, że proste połączenie powinno działać:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)
xortacja
źródło
4
Zrozumienie byłoby lepiej czytać i prawdopodobnie szybciej: print ' '.join(str(x) for x in range(1, 10)).
Mu Mind
Popieram użycie rozumienia listy. W takim przypadku łatwiej byłoby nawet czytać.
Austin Henley,
5

Kolejna odpowiedź, której używam w wersji 2.7, gdzie właśnie wypisuję „”. za każdym razem, gdy działa pętla (aby wskazać użytkownikowi, że rzeczy nadal działają):

print "\b.",

Drukuje „.” znaki bez spacji między nimi. Wygląda trochę lepiej i działa całkiem dobrze. \ B jest znakiem backspace dla tych, którzy się zastanawiają.

copeland3300
źródło
4

Tyle skomplikowanych odpowiedzi. Jeśli masz Python 3, po prostu umieść \rna początku wydruku i dodaj end='', flush=Truedo niego:

import time

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

To napisze 0 foo bar, a potem 1 foo baritd., W miejscu.

Hugh Perkins
źródło
Dziękuję, właśnie tego potrzebowałemprint('\r' + filename + " ", end = '', flush=True)
McPeppr
3

Aby liczby się zastąpiły, możesz zrobić coś takiego:

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

Powinno to działać, dopóki numer jest wydrukowany w pierwszej kolumnie.

EDYCJA: Oto wersja, która będzie działać, nawet jeśli nie jest wydrukowana w pierwszej kolumnie.

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

Powinienem zauważyć, że ten kod został przetestowany i działa dobrze w Pythonie 2.5 w systemie Windows, w konsoli Windows. Według niektórych innych może być konieczne przepłukanie standardowego wejścia, aby zobaczyć wyniki. YMMV.

Adam Crossland
źródło
3

„Nawiasem mówiąc ... Jak go odświeżyć za każdym razem, aby wydrukować mi w jednym miejscu, wystarczy zmienić numer.”

To naprawdę trudny temat. Co za zack zasugerował (wysyłanie kodów sterujących konsoli), jest jednym ze sposobów na osiągnięcie tego.

Możesz użyć (n) przekleństw, ale działa to głównie na * nixes.

W systemie Windows (i tutaj jest interesująca część), o której rzadko wspomina się (nie rozumiem dlaczego) można używać powiązań Python z WinAPI ( http://sourceforge.net/projects/pywin32/ również domyślnie z ActivePython) - to nie jest tak ciężko i działa dobrze. Oto mały przykład:

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 )

Lub, jeśli chcesz użyć print(instrukcja lub funkcja, bez różnicy):

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 moduł pozwala robić o wiele ciekawsze rzeczy z konsolą Windows ... Nie jestem wielkim fanem WinAPI, ale ostatnio zdałem sobie sprawę, że przynajmniej połowa mojej niechęci do niego była spowodowana pisaniem kodu WinAPI w C - powiązania pythonowe są znacznie łatwiejszy w użyciu.

Wszystkie pozostałe odpowiedzi są oczywiście świetne i pytoniczne, ale ... Co jeśli chciałbym wydrukować na poprzedniej linii? Lub napisz tekst wielowierszowy, niż go wyczyść i napisz te same wiersze ponownie? Moje rozwiązanie to umożliwia.

Cji
źródło
2

dla Python 2.7

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

dla Python 3

for x in range(0, 3):
    print(x, end=" ")
Adnan Ghaffar
źródło
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
źródło
0

Jeśli chcesz tylko wydrukować liczby, możesz uniknąć pętli.

# 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 zajęło 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 99 100 zajęło 491.466823551ms

Mahmoud Kassem
źródło
Powinien być jeszcze szybszy ze zrozumieniem listy zamiast map.
cji
Tak, dobre przykłady. Podoba mi się, ale muszę pokazać wynik analizy. Najpierw liczę pozycje w bazie danych, a następnie drukuję, ile pozostało.
Pol
0

Najlepszym sposobem na osiągnięcie tego jest użycie \r postaci

Po prostu wypróbuj poniższy kod:

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
źródło
0

W Pythonie 3 możesz to zrobić w ten sposób:

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

Wyjścia:

1 2 3 4 5 6 7 8 9 

Krotka: Możesz zrobić to samo z krotką:

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

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

Wyjścia:

1 - 2 - 3 - 4 - 5 - 

Inny przykład:

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

Wyjścia:

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

Możesz nawet rozpakować krotkę w ten sposób:

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)   

Wyjścia:

1 2
A B
3 4
Cat Dog

inna odmiana:

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

Wyjścia:

1
2


A
B


3
4


Cat
Dog
Stryker
źródło
Wypróbowałem wszystkie przykłady tutaj i żaden nie działa w Pythonie 3.8. Uzyskaj więcej odpowiedzi.
KOTZ
Przetestowałem to z pytonem 3.7
Stryker
Chodzi mi o to, że żadna z tych opcji nie zastępuje ostatniej liczby, jak sugerowano na końcu pytania.
KOTZ
0

Przecinek na końcu instrukcji print pomija nowy wiersz.

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

ale to nie zastępuje.

eruciform
źródło
0

Dla tych, którzy walczą tak samo jak ja, wymyśliłem następujące, które wydają się działać zarówno w Pythonie 3.7.4, jak i 3.5.2.

Rozszerzyłem zakres ze 100 do 1 000 000, ponieważ działa on bardzo szybko i możesz nie widzieć wyniku. Wynika to z tego, że jednym efektem ubocznym ustawienia end='\r'jest to, że końcowa iteracja pętli usuwa wszystkie dane wyjściowe. Potrzebna była dłuższa liczba, aby wykazać, że to działa. Ten wynik może nie być pożądany we wszystkich przypadkach, ale w moim przypadku był w porządku, a OP nie określił w ten czy inny sposób. Można to potencjalnie obejść za pomocą instrukcji if, która ocenia długość iterowanej tablicy itp. Kluczem do uruchomienia jej w moim przypadku było połączenie nawiasów "{}"z.format() . W przeciwnym razie to nie zadziałało.

Poniżej powinno działać tak, jak jest:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)
Struktura
źródło
0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Wyjście: 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, 22, 22, 29, 29, 30, 3, 3, 33,34,35,36,37,38,39,40, 41,42,43,44,45,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,96,96,98

Alex
źródło
0

Lub jeszcze prościej:

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

end="\r" nadpisze od początku [0:] pierwszego wydruku.

Evan Schwartzentruber
źródło