Apakah buffering output diaktifkan secara default pada interpreter Python sys.stdout
?
Jika jawabannya positif, apa saja cara untuk menonaktifkannya?
Saran sejauh ini:
- Gunakan
-u
saklar baris perintah - Bungkus
sys.stdout
sebuah objek yang memerah setelah setiap penulisan - Setel
PYTHONUNBUFFERED
env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
Apakah ada cara lain untuk mengatur beberapa flag global dalam sys
/ secara sys.stdout
terprogram selama eksekusi?
-u
adalah itu tidak akan berfungsi untuk bytecode yang dikompilasi atau untuk aplikasi dengan__main__.py
file sebagai titik masuk.Jawaban:
Dari jawaban Magnus Lycka di milis :
sumber
#!/usr/bin/env python -u
tidak bekerja !! lihat di sini__getattr__
hanya untuk menghindari warisan ?!iter()
bukanwhile
lingkaran:for line in iter(pipe.readline, ''):
. Anda tidak memerlukannya di Python 3 di manafor line in pipe:
menghasilkan sesegera mungkin.Saya lebih suka memasukkan jawaban saya di Bagaimana menyiram output dari fungsi cetak? atau dalam fungsi cetak Python yang mengguyur buffer ketika dipanggil? , tetapi karena mereka ditandai sebagai duplikat dari yang ini (apa yang saya tidak setuju), saya akan menjawabnya di sini.
Sejak Python 3.3, print () mendukung argumen kata kunci "flush" ( lihat dokumentasi ):
sumber
Penghargaan: "Sebastian", di suatu tempat di milis Python.
sumber
flush=True
parameter agarprint()
berfungsi sejak Python 3.3.os.fdopen(sys.stdout.fileno(), 'wb', 0)
(perhatikanb
untuk biner) danflush=True
bekerja untuk saya di 3.6.4. Namun, jika Anda menggunakan subproses untuk memulai skrip lain, pastikan Anda telah menentukanpython3
, jika Anda memiliki beberapa instance python yang diinstal.os.fdopen(sys.stdout.fileno(), 'wb', 0)
Anda berakhir dengan objek file biner, bukanTextIO
aliran. Anda harus menambahkan aTextIOWrapper
ke dalam campuran (pastikan untuk memungkinkanwrite_through
untuk menghilangkan semua buffer, atau gunakanline_buffering=True
untuk hanya menyiram pada baris baru).Ya itu.
Anda dapat menonaktifkannya di commandline dengan tombol "-u".
Atau, Anda dapat memanggil .flush () di sys.stdout pada setiap penulisan (atau membungkusnya dengan objek yang melakukan ini secara otomatis)
sumber
Ini berkaitan dengan jawaban Cristóvão D. Sousa, tetapi saya belum bisa berkomentar.
Cara mudah untuk menggunakan
flush
argumen kata kunci Python 3 agar selalu memiliki keluaran yang tidak dibangun adalah:setelah itu, hasil cetak akan selalu menyiram output secara langsung (kecuali
flush=False
diberikan).Perhatikan, (a) bahwa ini menjawab pertanyaan hanya sebagian karena tidak mengarahkan semua output. Tapi saya kira
print
adalah cara yang paling umum untuk membuat output kestdout
/stderr
dalam python, jadi 2 baris ini menutupi sebagian besar kasus penggunaan.Perhatikan (b) bahwa itu hanya bekerja di modul / skrip tempat Anda mendefinisikannya. Ini bisa baik ketika menulis modul karena tidak mengacaukannya
sys.stdout
.Python 2 tidak memberikan
flush
argumen, tetapi Anda bisa meniruprint
fungsi tipe-Python 3 seperti yang dijelaskan di sini https://stackoverflow.com/a/27991478/3734258 .sumber
flush
kwarg di python2.Tanpa menyimpan sys.stdout lama, disable_stdout_buffering () tidak idempoten, dan beberapa panggilan akan menghasilkan kesalahan seperti ini:
Kemungkinan lain adalah:
(Menambahkan ke gc.garbage bukanlah ide yang bagus karena itu adalah siklus yang tidak menyenangkan, dan Anda mungkin ingin memeriksanya.)
sumber
stdout
masih hidupsys.__stdout__
seperti yang disarankan beberapa orang, masalah sampah tidak perlu, kan? Ini trik yang keren.ValueError: can't have unbuffered text I/O
saat memanggilprint()
.Karya-karya berikut di Python 2.6, 2.7, dan 3.2:
sumber
OSError: [Errno 29] Illegal seek
untuk garissys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
Ya, ini diaktifkan secara default. Anda dapat menonaktifkannya dengan menggunakan opsi -u pada baris perintah saat memanggil python.
sumber
Anda juga dapat menjalankan Python dengan utilitas stdbuf :
stdbuf -oL python <script>
sumber
-oL
dimungkinkan) masih penyangga - lihat f / e stackoverflow.com/questions/58416853/… , menanyakan mengapaend=''
membuat keluaran tidak lagi segera ditampilkan.print(..., end='', flush=True)
mana itu improtant? OTOH, ketika beberapa program menulis ke output yang sama secara bersamaan, trade-off cenderung bergeser dari melihat kemajuan langsung menjadi mengurangi campur-baur output, dan line buffering menjadi menarik. Jadi mungkin itu adalah lebih baik untuk tidak menulis eksplisitflush
dan kontrol penyangga eksternal?flush
. Kontrol buffering eksternal harusDalam Python 3, Anda dapat menambal-kera fungsi cetak, untuk selalu mengirim flush = True:
Seperti yang ditunjukkan dalam komentar, Anda dapat menyederhanakan ini dengan mengikat parameter flush ke sebuah nilai, melalui
functools.partial
:sumber
functools.partial
?print = functools.partial(print, flush=True)
bekerja dengan baik untuk saya.import builtins; builtins.print = partial(print, flush=True)
Anda juga dapat menggunakan fcntl untuk mengubah flag file secara langsung.
sumber
Dimungkinkan untuk mengganti hanya
write
metodesys.stdout
dengan metode yang memanggilflush
. Implementasi metode yang disarankan di bawah ini.Nilai
w
argumen default akan menyimpanwrite
referensi metode asli . Setelahwrite_flush
ditentukan, dokumen asliwrite
mungkin diganti.Kode mengasumsikan yang
stdout
diimpor dengan cara inifrom sys import stdout
.sumber
Anda dapat membuat file yang tidak dibangun dan menugaskan file ini ke sys.stdout.
Anda tidak dapat secara ajaib mengubah stdout yang disediakan sistem; karena ini dipasok ke program python Anda oleh OS.
sumber
Varian yang berfungsi tanpa menabrak (setidaknya pada win32; python 2.7, ipython 0.12) kemudian dipanggil selanjutnya (beberapa kali):
sumber
sys.stdout is sys.__stdout__
alih - alih mengandalkan objek pengganti yang memiliki atribut nama?(Saya sudah mengirim komentar, tapi entah bagaimana hilang. Jadi, lagi :)
Seperti yang saya perhatikan, CPython (setidaknya di Linux) berperilaku berbeda tergantung dari mana outputnya. Jika pergi ke tty, maka output memerah setelah masing-masing '
\n'
Jika pergi ke pipa / proses, maka buffered dan Anda dapat menggunakan
flush()
solusi berbasis atau opsi -u yang direkomendasikan di atas.Sedikit terkait dengan buffering keluaran:
Jika Anda mengulangi garis di input dengan
for line in sys.stdin:
...
maka untuk implementasi dalam CPython akan mengumpulkan input untuk sementara dan kemudian menjalankan loop body untuk sekelompok jalur input. Jika skrip Anda hendak menulis output untuk setiap baris input, ini mungkin terlihat seperti buffering output tetapi sebenarnya batching, dan karena itu, tidak ada satu pun
flush()
, dll teknik akan membantu itu. Menariknya, Anda tidak memiliki perilaku ini dalam pypy . Untuk menghindari ini, Anda bisa menggunakanwhile True: line=sys.stdin.readline()
...
sumber
for line in sys.stdin
vs.for line in iter(sys.stdin.readline, "")
for line in sys.stdin
memberikan respons yang tertunda)Salah satu cara untuk mendapatkan keluaran yang tidak bermasalah adalah dengan menggunakan
sys.stderr
alih-alihsys.stdout
atau hanya memanggilsys.stdout.flush()
untuk secara eksplisit memaksa penulisan terjadi.Anda dapat dengan mudah mengarahkan ulang semua yang dicetak dengan melakukan:
Atau untuk mengarahkan ulang hanya untuk
print
pernyataan tertentu :Untuk mengatur ulang stdout, Anda cukup melakukan:
sumber