Bagaimana menyiram keluaran fungsi cetak?

1216

Bagaimana cara memaksa fungsi cetak Python untuk menampilkan ke layar?

Ini bukan duplikat Nonaktifkan buffering output - pertanyaan yang ditautkan mencoba output yang tidak dibangun, sementara ini lebih umum. Jawaban teratas dalam pertanyaan itu terlalu kuat atau terlibat untuk yang ini (itu bukan jawaban yang baik untuk ini), dan pertanyaan ini dapat ditemukan di Google oleh seorang pemula.

Walter Nissen
sumber

Jawaban:

1428

Pada Python 3, printdapat mengambil flushargumen opsional

print("Hello world!", flush=True)

Pada Python 2 Anda harus melakukannya

import sys
sys.stdout.flush()

setelah menelepon print. Secara default, printcetak ke sys.stdout(lihat dokumentasi untuk informasi lebih lanjut tentang objek file ).

CesarB
sumber
347

Berjalan python -h, saya melihat opsi baris perintah :

-u: stdout dan stderr biner yang tidak dibangun; juga PYTHONUNBUFFERED = x lihat halaman manual untuk detail tentang buffering internal yang berkaitan dengan '-u'

Inilah dokumen yang relevan .

Gimel
sumber
320

Karena Python 3.3, Anda dapat memaksa print()fungsi normal untuk menyiram tanpa perlu menggunakan sys.stdout.flush(); cukup setel argumen kata kunci "flush" menjadi true. Dari dokumentasi :

cetak (* objek, sep = '', end = '\ n', file = sys.stdout, flush = Salah)

Mencetak objek ke file stream, dipisahkan dengan sep dan diikuti oleh ujung. September, akhiri dan ajukan, jika ada, harus diberikan sebagai argumen kata kunci.

Semua argumen non-kata kunci dikonversi ke string seperti str () dilakukan dan ditulis ke aliran, dipisahkan oleh sep dan diikuti oleh akhir. Baik sep dan akhir harus berupa string; mereka juga bisa menjadi Tidak Ada, yang berarti menggunakan nilai default. Jika tidak ada objek yang diberikan, print () hanya akan menulis akhir.

Argumen file harus berupa objek dengan metode tulis (string); jika tidak ada atau Tidak ada, sys.stdout akan digunakan. Apakah output buffered biasanya ditentukan oleh file, tetapi jika argumen kata kunci flush benar, aliran secara paksa dihapus.

Eugene Sajine
sumber
198

Bagaimana menyiram hasil cetak Python?

Saya menyarankan lima cara untuk melakukan ini:

  • Dalam Python 3, panggil print(..., flush=True)(argumen flush tidak tersedia dalam fungsi cetak Python 2, dan tidak ada analog untuk pernyataan cetak).
  • Panggil file.flush()file output (kita dapat membungkus fungsi cetak python 2 untuk melakukan ini), misalnya,sys.stdout
  • terapkan ini untuk setiap panggilan fungsi cetak dalam modul dengan fungsi parsial,
    print = partial(print, flush=True)diterapkan pada modul global.
  • terapkan ini pada proses dengan flag ( -u) yang diteruskan ke perintah juru bahasa
  • terapkan ini ke setiap proses python di lingkungan Anda dengan PYTHONUNBUFFERED=TRUE(dan hapus variabel untuk membatalkan ini).

Python 3.3+

Menggunakan Python 3.3 atau lebih tinggi, Anda bisa memberikan flush=Trueargumen kata kunci untuk printfungsi ini:

print('foo', flush=True) 

Python 2 (atau <3.3)

Mereka tidak mendukung flushargumen ke Python 2.7 Jadi jika Anda menggunakan Python 2 (atau kurang dari 3,3), dan ingin kode yang kompatibel dengan 2 dan 3, boleh saya sarankan kode kompatibilitas berikut. (Perhatikan __future__impor harus di / sangat "dekat bagian atas modul Anda "):

from __future__ import print_function
import sys

if sys.version_info[:2] < (3, 3):
    old_print = print
    def print(*args, **kwargs):
        flush = kwargs.pop('flush', False)
        old_print(*args, **kwargs)
        if flush:
            file = kwargs.get('file', sys.stdout)
            # Why might file=None? IDK, but it works for print(i, file=None)
            file.flush() if file is not None else sys.stdout.flush()

Kode kompatibilitas di atas akan mencakup sebagian besar kegunaan, tetapi untuk perawatan yang jauh lebih menyeluruh, lihat sixmodul .

Atau, Anda bisa menelepon file.flush()setelah mencetak, misalnya, dengan pernyataan cetak dengan Python 2:

import sys
print 'delayed output'
sys.stdout.flush()

Mengubah default dalam satu modul menjadi flush=True

Anda dapat mengubah default untuk fungsi cetak dengan menggunakan functools.partial pada lingkup global modul:

import functools
print = functools.partial(print, flush=True)

jika Anda melihat fungsi parsial baru kami, setidaknya dalam Python 3:

>>> print = functools.partial(print, flush=True)
>>> print
functools.partial(<built-in function print>, flush=True)

Kita bisa melihatnya berfungsi seperti biasa:

>>> print('foo')
foo

Dan kita benar-benar dapat mengganti default baru:

>>> print('foo', flush=False)
foo

Perhatikan lagi, ini hanya mengubah lingkup global saat ini, karena nama cetak pada lingkup global saat ini akan menaungi printfungsi bawaan (atau membatalkan referensi fungsi kompatibilitas, jika menggunakan satu di Python 2, dalam lingkup global saat ini).

Jika Anda ingin melakukan ini di dalam fungsi alih-alih pada lingkup global modul, Anda harus memberinya nama yang berbeda, misalnya:

def foo():
    printf = functools.partial(print, flush=True)
    printf('print stuff like this')

Jika Anda mendeklarasikannya sebagai global dalam suatu fungsi, Anda mengubahnya di namespace global modul, jadi Anda harus meletakkannya di namespace global, kecuali perilaku spesifik itu persis seperti yang Anda inginkan.

Mengubah default untuk proses

Saya pikir opsi terbaik di sini adalah menggunakan -uflag untuk mendapatkan output yang tidak dikompromikan.

$ python -u script.py

atau

$ python -um package.module

Dari dokumen :

Paksa stdin, stdout dan stderr untuk sepenuhnya tidak terganggu. Pada sistem yang penting, juga letakkan stdin, stdout dan stderr dalam mode biner.

Perhatikan bahwa ada buffering internal di file.readlines () dan File Objects (untuk baris di sys.stdin) yang tidak dipengaruhi oleh opsi ini. Untuk mengatasinya, Anda harus menggunakan file.readline () di dalam 1: loop sementara.

Mengubah default untuk lingkungan operasi shell

Anda bisa mendapatkan perilaku ini untuk semua proses python di lingkungan atau lingkungan yang mewarisi dari lingkungan jika Anda mengatur variabel lingkungan ke string yang kosong:

misalnya, di Linux atau OSX:

$ export PYTHONUNBUFFERED=TRUE

atau Windows:

C:\SET PYTHONUNBUFFERED=TRUE

dari dokumen :

PYTHONUNBUFFERED

Jika ini disetel ke string yang tidak kosong, itu sama dengan menentukan opsi -u.


Tambahan

Inilah bantuan pada fungsi cetak dari Python 2.7.12 - perhatikan bahwa tidak ada flush argumen:

>>> from __future__ import print_function
>>> help(print)
print(...)
    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.
Aaron Hall
sumber
Untuk migrasi yang aneh dari versi Python yang lebih rendah: __future__versi tidak termasuk flushkarena "argumen flush ditambahkan dalam Python 3.3 (setelah cetak () di-backport ke 2.7 melalui impor di masa mendatang)" bugs.python.org/issue28458
Oliver
69

Juga seperti yang disarankan di blog ini, seseorang dapat membuka kembali sys.stdoutdalam mode tidak dibangun:

sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Masing stdout.write- masing dan printoperasi akan secara otomatis memerah sesudahnya.

Antony Hatchkins
sumber
2
Pada Ubuntu 12.04 dalam python 2.7 ini memberi sayaUnsupportedOperation: IOStream has no fileno.
drevicko
3
Aduh, Python 3 ditemukan. Itu tidak akan membiarkan saya mengeksekusi kode ini!
EKons
Saya bingung dengan ungkapan ini. Setelah Anda melakukan ini, bukankah sekarang ada dua objek seperti File (sys.stdout asli dan sys.stdout baru) yang keduanya mengira mereka "memiliki" fileno? Itu buruk, bukan?
Don Hatch
62

Dengan Python 3.x print()fungsi telah diperluas:

print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)

Jadi, Anda bisa melakukan:

print("Visiting toilet", flush=True)

Entri Python Documents

Noah Krasser
sumber
36

Menggunakan -usaklar baris perintah berfungsi, tetapi sedikit canggung. Ini berarti bahwa program tersebut berpotensi berperilaku salah jika pengguna memanggil skrip tanpa -uopsi. Saya biasanya menggunakan kebiasaan stdout, seperti ini:

class flushfile:
  def __init__(self, f):
    self.f = f

  def write(self, x):
    self.f.write(x)
    self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

... Sekarang semua printpanggilan Anda (yang menggunakan sys.stdoutsecara implisit), akan otomatis flushdiedit.

Dan Lenski
sumber
4
Saya sarankan tidak mewarisi dari file dan kemudian mendelegasikan ke stdout dengan menambahkan. def __getattr__(self,name): return object.__getattribute__(self.f, name)
diedthreetimes
2
Tanpa perubahan yang disarankan oleh komentar oleh @diedthreetimes, saya mendapatkan "ValueError: operasi I / O pada file yang ditutup"
blueFast
19

Mengapa tidak mencoba menggunakan file yang tidak dibuat-buat?

f = open('xyz.log', 'a', 0)

ATAU

sys.stdout = open('out.log', 'a', 0)
Nakilon
sumber
1
Dia tidak ingin membuat file yang tidak di-buffer; dia ingin membuat stdout yang ada (dialihkan ke konsol, terminal atau apa pun: ini tidak boleh diubah) tidak bermasalah.
blueFast
13

Ide Dan tidak cukup berhasil:

#!/usr/bin/env python
class flushfile(file):
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

print "foo"

Hasil:

Traceback (most recent call last):
  File "./passpersist.py", line 12, in <module>
    print "foo"
ValueError: I/O operation on closed file

Saya percaya masalahnya adalah itu mewarisi dari kelas file, yang sebenarnya tidak perlu. Menurut dokumen untuk sys.stdout:

stdout dan stderr tidak harus berupa objek file bawaan: objek apa pun dapat diterima asalkan memiliki metode write () yang membutuhkan argumen string.

sangat berubah

class flushfile(file):

untuk

class flushfile(object):

membuatnya bekerja dengan baik.

Kamil Kisiel
sumber
17
Tidak ada suara karena ini solusi IS @ Dan ... (Anda lebih baik harus mengomentari posting Dan daripada menyalin solusinya)
gecco
8

Ini adalah versi saya, yang juga menyediakan writelines () dan fileno ():

class FlushFile(object):
    def __init__(self, fd):
        self.fd = fd

    def write(self, x):
        ret = self.fd.write(x)
        self.fd.flush()
        return ret

    def writelines(self, lines):
        ret = self.writelines(lines)
        self.fd.flush()
        return ret

    def flush(self):
        return self.fd.flush

    def close(self):
        return self.fd.close()

    def fileno(self):
        return self.fd.fileno()
guettli
sumber
Solusi unggul. Dan itu berhasil. Diuji pada Python 3.4.0. Dengan versi lain, yang berasal dari file, saya mendapatkan kesalahan. Tidak ada filekelas.
Colin D Bennett
6

Dalam Python 3 Anda dapat menimpa fungsi cetak dengan pengaturan default ke flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)
pengguna263387
sumber
2
jawaban ini tampaknya sedikit ringan mengingat semua tanggapan berkualitas tinggi lainnya. Anda mungkin ingin menambahkan sedikit lebih banyak ke dalamnya.
Titik koma dan Lakban
5

Saya melakukannya seperti ini di Python 3.4:

'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end="")
message('I am flushing out now...')
kmario23
sumber
2

Saya pertama kali berjuang untuk memahami bagaimana opsi flush bekerja. Saya ingin melakukan 'memuat tampilan' dan di sini adalah solusi yang saya temukan:

for i in range(100000):
    print('{:s}\r'.format(''), end='', flush=True)
    print('Loading index: {:d}/100000'.format(i+1), end='')

Baris pertama membersihkan cetakan sebelumnya dan baris kedua mencetak pesan baru yang diperbarui. Saya tidak tahu apakah ada sintaks satu baris di sini.

Guillaume Mougeot
sumber