Cetak dalam satu baris secara dinamis

306

Saya ingin membuat beberapa pernyataan yang memberikan output standar tanpa melihat baris baru di antara pernyataan.

Secara khusus, misalkan saya punya:

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

Hasilnya adalah:

1
2
3
4
.
.
.

Bagaimana ini bisa terlihat seperti:

1 2 3 4 5 ...

Lebih baik lagi, mungkinkah mencetak nomor tunggal di atas angka terakhir, jadi hanya satu nomor yang ada di layar pada satu waktu?

Pol
sumber

Jawaban:

482

Ubah print itemke:

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

Jika Anda ingin mencetak data secara dinamis, gunakan sintaks berikut:

  • print(item, sep=' ', end='', flush=True) dalam Python 3
ewall
sumber
Dari http://docs.python.org/reference/simple_stmts.html#print :> '\n'Karakter ditulis di bagian akhir, kecuali printpernyataan berakhir dengan koma. Ini adalah satu-satunya tindakan jika pernyataan itu hanya berisi kata kunci print.
ewall
5
FYI: print (item, end = "") dapat digunakan dalam Python2.7 dengan menambahkan 'from future import print_function' di atas file.
Hec
2
Tetapi sayangnya flushtidak berhasil from __future__ import print_function.
Timmmm
@ wall jika saya akan melakukannya print(item, end=", ")kemudian juga menambahkan ,ke item terakhir bagaimana cara mencegahnya menambahkan ,ke item terakhir
MarcoBianchi
@SamirTendulkar Jika Anda menggunakan for-loop seperti pertanyaan awal, Anda dapat membuat case khusus untuk menangani item terakhir dalam daftar secara berbeda ...
ewall
156

Ngomong-ngomong ...... Cara menyegarkan setiap kali sehingga mencetak mi di satu tempat hanya mengubah nomor.

Secara umum, cara untuk melakukannya adalah dengan kode kontrol terminal . Ini adalah kasus yang sangat sederhana, di mana Anda hanya memerlukan satu karakter khusus: U + 000D CARRIAGE RETURN, yang ditulis '\r'dalam Python (dan banyak bahasa lainnya). Berikut ini adalah contoh lengkap berdasarkan kode Anda:

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

Beberapa hal tentang ini yang mungkin mengejutkan:

  • The \rberjalan pada awal string sehingga, sementara program ini berjalan, kursor akan selalu setelah nomor. Ini bukan hanya kosmetik: beberapa emulator terminal menjadi sangat bingung jika Anda melakukannya sebaliknya.
  • Jika Anda tidak menyertakan baris terakhir, maka setelah program berakhir, shell Anda akan mencetak prompt di atas nomor tersebut.
  • Ini stdout.flushdiperlukan pada beberapa sistem, atau Anda tidak akan mendapatkan output apa pun. Sistem lain mungkin tidak memerlukannya, tetapi tidak membahayakan.

Jika ternyata ini tidak berhasil, hal pertama yang harus Anda curigai adalah emulator terminal Anda bermasalah. Program vttest dapat membantu Anda mengujinya.

Anda bisa mengganti stdout.writedengan printpernyataan tetapi saya memilih untuk tidak mencampur printdengan penggunaan langsung objek file.

zwol
sumber
Apa fungsi meen flush ()? Karena itu bekerja untuk saya tanpa fungsi itu!
Pol
1
Biasanya, file Python objek mengumpulkan data sehingga mereka dapat mengirimkannya ke sistem operasi dalam potongan besar. Ini adalah apa yang Anda inginkan untuk mengakses file pada disk, biasanya, tetapi ini mengganggu tugas semacam ini. flush()memaksa file untuk mengirim apa pun yang ada ke sistem operasi sekarang. Saya terkejut itu bekerja untuk Anda tanpa itu - itu tidak bekerja untuk saya sampai saya menambahkannya.
zwol
1
@ user1995839 Ada kode kontrol untuk menyembunyikan kursor, tetapi jika Anda akan melakukannya saya sangat menyarankan Anda gunakan ncursesuntuk melakukannya.
zwol
1
sys.stdout.flush()tampaknya tidak baik pada saya FreebsddenganPython 2.7
Hakim
1
Perhatikan bahwa carriage return tidak berfungsi dengan benar dalam Python REPL (setidaknya untuk saya, di Ubuntu); Anda harus menjalankan skrip , bukan hanya menjalankan perintah REPL, agar semua ini berfungsi.
Mark Amery
50

Gunakan print item,untuk membuat pernyataan cetak menghilangkan baris baru.

Dalam Python 3, itu print(item, end=" ").

Jika Anda ingin setiap angka ditampilkan di tempat yang sama, gunakan misalnya (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),

Dalam Python 3, ini sedikit lebih rumit; di sini Anda perlu menyiram sys.stdoutatau tidak akan mencetak apa pun sampai setelah loop selesai:

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
sumber
Sebenarnya, bagi saya sepertinya solusi Anda akan mencetak jumlah backspace yang sama setiap kali. Jadi, jika to 20, itu akan mencetak backspace tambahan saat mencetak angka 1..9. Bukankah Anda seharusnya menghitung angka di dalam loop dan mendasarkannya dari nilai i?
Adam Crossland
Itu membenarkan nomor dan selalu menghapus semuanya. Saya belum menguji apakah lebih cepat untuk melakukan itu atau menghitung di setiap iterasi berapa banyak digit yang harus dihapus sekarang.
Tim Pietzcker
Atau, mendasarkannya dari nilai i ke akun sebelumnya ketika jumlah digit berubah.
Adam Crossland
Ah, ya, saya sudah terlalu melihat-kanan pembenaran. Solusi yang bagus
Adam Crossland
Kedengarannya cukup rumit. Saya mungkin tidak akan mengerti apa yang telah saya lakukan di sana jika saya harus melihat kode saya setahun dari sekarang. (Hanya harus membaca program saya tulis pada tahun 2007 - Saya sangat senang saya menulisnya dengan Python.)
Tim Pietzcker
16

Seperti contoh lainnya,
saya menggunakan pendekatan yang serupa tetapi alih-alih menghabiskan waktu menghitung panjang keluaran terakhir, dll.

Saya cukup menggunakan kode ANSI lolos untuk kembali ke awal baris dan kemudian menghapus seluruh baris sebelum mencetak output status saya saat ini.

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

Untuk digunakan dalam loop iterasi Anda, Anda hanya akan memanggil sesuatu seperti:

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

Lihat lebih lanjut di sini

Matius
sumber
14

Anda dapat menambahkan tanda koma pada pernyataan cetak Anda untuk mencetak spasi alih-alih baris baru di setiap iterasi:

print item,

Atau, jika Anda menggunakan Python 2.6 atau yang lebih baru, Anda dapat menggunakan fungsi cetak baru, yang akan memungkinkan Anda untuk menentukan bahwa tidak ada spasi di akhir setiap item yang sedang dicetak (atau memungkinkan Anda menentukan apa pun yang Anda inginkan) ingin):

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

Akhirnya, Anda dapat menulis langsung ke output standar dengan mengimpornya dari modul sys, yang mengembalikan objek seperti file:

from sys import stdout
...
stdout.write( str(item) )
Eli Courtwright
sumber
13

perubahan

print item

untuk

print "\033[K", item, "\r",
sys.stdout.flush()
  • "\ 033 [K" membersihkan ke akhir baris
  • the, kembali ke awal baris
  • pernyataan flush memastikan itu muncul segera sehingga Anda mendapatkan output real-time.
Anak sungai
sumber
Ini bagus untuk Python 2.7. Bisakah Anda memberikan referensi ke tempat Anda belajar tentang \033[Kkode? Saya ingin belajar lebih banyak tentang mereka.
Klik
printsudah memerah secara internal. Tidak perlu menyebutnya. printberbeda dari di sys.stdout.write()mana Anda harus membuka layar
Gabriel Fair
5

Saya pikir bergabung sederhana harus berfungsi:

nl = []
for x in range(1,10):nl.append(str(x))
print ' '.join(nl)
xortion
sumber
4
Sebuah pemahaman akan membaca lebih baik dan mungkin lebih cepat: print ' '.join(str(x) for x in range(1, 10)).
Mu Mind
Saya kedua menggunakan pemahaman daftar. Dalam hal ini akan membuatnya lebih mudah dibaca.
Austin Henley
5

Jawaban lain yang saya gunakan pada 2.7 di mana saya hanya mencetak "." setiap kali loop berjalan (untuk menunjukkan kepada pengguna bahwa hal-hal masih berjalan) adalah ini:

print "\b.",

Ini mencetak "." karakter tanpa spasi di antara masing-masing. Terlihat sedikit lebih baik dan bekerja dengan cukup baik. \ B adalah karakter backspace untuk mereka yang bertanya-tanya.

copeland3300
sumber
4

Begitu banyak jawaban yang rumit. Jika Anda memiliki python 3, cukup letakkan \rdi awal cetakan, dan tambahkan end='', flush=True:

import time

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

Ini akan menulis 0 foo bar, lalu 1 foo bardll, di tempat.

Hugh Perkins
sumber
Terima kasih, itulah yang saya butuhkanprint('\r' + filename + " ", end = '', flush=True)
McPeppr
3

Untuk membuat angka saling menimpa, Anda dapat melakukan sesuatu seperti ini:

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

Itu harus bekerja selama nomor dicetak di kolom pertama.

Sunting: Ini adalah versi yang akan berfungsi walaupun tidak dicetak di kolom pertama.

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

Saya harus mencatat bahwa kode ini telah diuji dan berfungsi dengan baik di Python 2.5 di Windows, di konsol WIndows. Menurut beberapa orang lain, pembilasan stdout mungkin diperlukan untuk melihat hasilnya. YMMV.

Adam Crossland
sumber
3

"Ngomong-ngomong ...... Cara menyegarkan setiap kali sehingga mencetak mi di satu tempat hanya mengubah nomor."

Itu topik yang sangat rumit. Apa yang disarankan Zack (mengeluarkan kode kontrol konsol) adalah salah satu cara untuk mencapai itu.

Anda dapat menggunakan (n) kutukan, tetapi itu bekerja terutama pada * nixes.

Pada Windows (dan inilah bagian yang menarik) yang jarang disebutkan (saya tidak mengerti mengapa) Anda dapat menggunakan binding Python ke WinAPI ( http://sourceforge.net/projects/pywin32/ juga dengan ActivePython secara default) - bukan itu sulit dan bekerja dengan baik. Ini sebuah contoh kecil:

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 )

Atau, jika Anda ingin menggunakan print(pernyataan atau fungsi, tidak ada perbedaan):

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 modul memungkinkan Anda untuk melakukan banyak hal yang lebih menarik dengan konsol windows ... Saya bukan penggemar berat WinAPI, tetapi baru-baru ini saya menyadari bahwa setidaknya setengah dari antipati saya terhadapnya disebabkan oleh penulisan kode WinAPI dalam C - pythonic bindings. lebih mudah digunakan.

Semua jawaban lain bagus dan pythonic, tentu saja, tapi ... Bagaimana jika saya ingin mencetak pada baris sebelumnya ? Atau menulis teks multiline, daripada menghapusnya dan menulis baris yang sama lagi? Solusi saya memungkinkan itu.

cji
sumber
2

untuk Python 2.7

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

untuk Python 3

for x in range(0, 3):
    print(x, end=" ")
Adnan Ghaffar
sumber
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
sumber
0

Jika Anda hanya ingin mencetak angka, Anda dapat menghindari lingkaran itu.

# 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 89 91 91 93 94 94 96 96 98 98 99 100 mengambil 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 89 91 91 93 94 94 96 96 98 98 99 100 mengambil 491.466823551ms

Mahmoud Kassem
sumber
Harus lebih cepat dengan pemahaman daftar daripada map.
cji
Ya, contoh bagus. Saya suka, tetapi saya harus menunjukkan hasil parsing. Pertama-tama saya menghitung item-item dalam basis data daripada mencetak berapa banyak yang tersisa.
Pol
0

Cara terbaik untuk mencapai ini adalah dengan menggunakan \rkarakter

Coba saja kode di bawah ini:

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
vital
sumber
0

Dengan Python 3 Anda bisa melakukannya dengan cara ini:

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

Keluaran:

1 2 3 4 5 6 7 8 9 

Tuple: Anda dapat melakukan hal yang sama dengan tuple:

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

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

Keluaran:

1 - 2 - 3 - 4 - 5 - 

Contoh lain:

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

Keluaran:

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

Anda bahkan dapat membongkar tuple Anda seperti ini:

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)   

Keluaran:

1 2
A B
3 4
Cat Dog

variasi lain:

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

Keluaran:

1
2


A
B


3
4


Cat
Dog
Stryker
sumber
Saya telah mencoba semua contoh di sini dan tidak ada yang berhasil di python 3.8 Silakan dapatkan lebih banyak jawaban.
KOTZ
Saya telah mengujinya dengan python 3.7
Stryker
Yang saya maksud adalah tidak ada opsi yang menimpa angka terakhir seperti yang disarankan pada akhir pertanyaan.
KOTZ
0

Koma di akhir pernyataan cetak menghilangkan baris baru.

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

tetapi ini tidak menimpa.

eruciform
sumber
0

Bagi mereka yang berjuang seperti yang saya lakukan, saya datang dengan berikut ini yang tampaknya bekerja di kedua python 3.7.4 dan 3.5.2.

Saya memperluas jangkauan dari 100 menjadi 1.000.000 karena berjalan sangat cepat dan Anda mungkin tidak melihat hasilnya. Ini karena satu efek samping dari pengaturan end='\r'adalah bahwa perulangan putaran akhir membersihkan semua output. Diperlukan angka yang lebih panjang untuk menunjukkan bahwa itu berhasil. Hasil ini mungkin tidak diinginkan dalam semua kasus, tetapi baik-baik saja di saya, dan OP tidak menentukan satu atau lain cara. Anda dapat menghindari ini dengan pernyataan if yang mengevaluasi panjang array yang di-iterasi, dll. Kunci untuk membuatnya berfungsi dalam kasus saya adalah dengan memasangkan kurung "{}"dengan .format(). Kalau tidak, itu tidak berhasil.

Di bawah ini harus berfungsi apa adanya:

#!/usr/bin/env python3

for item in range(1,1000000):
    print("{}".format(item), end='\r', flush=True)
Struktur
sumber
0
for item in range(1,100):
    if item==99:
        print(item,end='')
    else:
        print (item,end=',')

Output: 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

Alex
sumber
0

Atau bahkan lebih sederhana:

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

end="\r" akan menimpa dari awal [0:] cetakan pertama.

Evan Schwartzentruber
sumber