Baskı fonksiyonunun çıktısını nasıl temizleyebilirim?


1216

Python'un yazdırma işlevini ekrana çıkmaya nasıl zorlarım?

Bu, Çıktı arabelleğini devre dışı bırakmanın bir kopyası değildir - bu daha genel olsa da, bağlantılı soru arabelleğe alınmamış çıktı almaya çalışıyor. Bu sorudaki en iyi yanıtlar çok güçlü veya bununla ilgili (bu iyi yanıtlar değil) ve bu soru Google'da göreceli bir acemi tarafından bulunabilir.

Yanıtlar:


1428

Python 3'te printisteğe bağlı bir flushargüman alabilir

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

Python 2'de yapmanız gerekenler

import sys
sys.stdout.flush()

aradıktan sonra print. Varsayılan olarak, konumuna printyazdırır sys.stdout( dosya nesneleri hakkında daha fazla bilgi için belgelere bakın ).


346

Çalışırken python -h, bir komut satırı seçeneği görüyorum :

-u: tamponlanmamış ikili stdout ve stderr; Ayrıca PYTHONUNBUFFERED = x '-u' ile ilgili dahili arabelleğe alma hakkında ayrıntılar için man sayfasına bakın

İşte ilgili doküman .


320

Python 3.3 olduğundan, normal print()işlevi kullanmaya gerek kalmadan yıkamayı zorlayabilirsiniz sys.stdout.flush(); "flush" anahtar kelime bağımsız değişkenini true olarak ayarlamanız yeterlidir. Gönderen belgeler :

print (* nesneler, sep = '', end = '\ n', dosya = sys.stdout, flush = Yanlış)

Nesneleri akış dosyasına ayırarak, sep ve birbirinden sonra yazdırın. sep, end ve file, varsa, anahtar kelime bağımsız değişkenleri olarak verilmelidir.

Tüm anahtar kelime olmayan bağımsız değişkenler str () does gibi dizelere dönüştürülür ve akışa sep ile ayrılmış ve son olarak yazılır. Sep ve end dizeleri olmalıdır; Ayrıca Yok olabilir, bu da varsayılan değerleri kullanmak anlamına gelir. Herhangi bir nesne verilmezse, print () sadece sonlanır.

Dosya argümanı write (string) yöntemine sahip bir nesne olmalıdır; yoksa veya Yok ise, sys.stdout kullanılır. Çıktının arabelleğe alınıp alınmayacağı genellikle dosyaya göre belirlenir, ancak flush anahtar sözcüğü bağımsız değişkeni true olursa akış zorla temizlenir.


198

Python baskı çıktısını nasıl temizlerim?

Bunu yapmanın beş yolunu öneririm:

  • Python 3'te, call print(..., flush=True)(flush argümanı Python 2'nin yazdırma işlevinde kullanılamaz ve print deyimi için bir analog yoktur).
  • file.flush()Çıktı dosyasını arayın (bunu yapmak için python 2'nin yazdırma işlevini sarabiliriz), örneğin,sys.stdout

  • print = partial(print, flush=True)bunu, modüle global olarak uygulanan kısmi işlevli her yazdırma işlevi çağrısına uygulayın .
  • bunu -uinterpreter komutuna iletilen flag ( ) ile işleme uygulayın
  • bunu ortamınızdaki her python işlemine ile uygulayın PYTHONUNBUFFERED=TRUE(ve bunu geri almak için değişkenin ayarını kaldırın ).

Python 3.3+

Python 3.3 veya üstünü flush=Truekullanarak, printişleve bir anahtar kelime argümanı olarak girebilirsiniz :

print('foo', flush=True) 

Python 2 (veya <3.3)

flushPython 2.7'ye argümanı backport vermediler. Python 2 (veya 3.3'ten az) kullanıyorsanız ve hem 2 hem de 3 ile uyumlu kod istiyorsanız, aşağıdaki uyumluluk kodunu önerebilir miyim. ( __future__İçe aktarmanın / modülünüzün üst kısmında / çok yakınında olması gerektiğini unutmayın ):

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

Yukarıdaki uyumluluk kodu çoğu kullanımı kapsayacaktır, ancak çok daha kapsamlı bir tedavi için sixmodüle bakın .

Alternatif olarak, file.flush()yazdırdıktan sonra, örneğin Python 2'deki print ifadesiyle arayabilirsiniz :

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

Bir modüldeki varsayılan değeri flush=True

Bir modülün global kapsamındaki functools.partial komutunu kullanarak yazdırma işlevi için varsayılanı değiştirebilirsiniz:

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

yeni kısmi fonksiyonumuza bakarsanız, en azından Python 3'te:

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

Normal gibi çalıştığını görebiliriz:

>>> print('foo')
foo

Ve aslında yeni varsayılanı geçersiz kılabiliriz:

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

Yine, yalnızca geçerli global kapsamı değiştirdiğine dikkat edin, çünkü mevcut global kapsamdaki yazdırma adı yerleşik printişlevi gölgede bırakacaktır (veya Python 2'de bir tane kullanılıyorsa uyumluluk işlevini geçerli global kapsamdan farklı kılacaktır).

Bunu bir modülün global kapsamı yerine bir fonksiyonun içinde yapmak istiyorsanız, ona farklı bir isim vermelisiniz, örneğin:

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

Bir işlevde global olarak bildirirseniz, modülün global ad alanında değiştirirsiniz, bu nedenle, belirli bir davranış tam olarak istediğiniz şey olmadığı sürece, onu genel ad alanına koymanız gerekir.

İşlem için varsayılanı değiştirme

Bence buradaki en iyi seçenek, -uarabelleksiz çıktı almak için bayrağı kullanmak .

$ python -u script.py

veya

$ python -um package.module

Gönderen docs :

Stdin, stdout ve stderr'i tamamen arabelleksiz olmaya zorlayın. Önemli olduğu sistemlerde, stdin, stdout ve stderr'i ikili moda da koyun.

Bu seçenekten etkilenmeyen file.readlines () ve Dosya Nesnelerinde (sys.stdin'deki satır için) dahili arabellekleme olduğuna dikkat edin. Bu sorunu gidermek için, bir süre 1: döngü içinde file.readline () kullanmak isteyeceksiniz.

Kabuk işletim ortamı için varsayılan değeri değiştirme

Ortam değişkenini boş olmayan bir dizeye ayarlarsanız, ortamdaki veya ortamdaki devralınan tüm python işlemleri için bu davranışı alabilirsiniz:

örneğin, Linux veya OSX'te:

$ export PYTHONUNBUFFERED=TRUE

veya Windows:

C:\SET PYTHONUNBUFFERED=TRUE

dan docs :

PYTHONUNBUFFERED

Bu boş olmayan bir dizeye ayarlanırsa, -u seçeneğini belirtmeye eşdeğerdir.


ek

İşte Python 2.7.12 yazdırma işlevini yardım var - olduğunu not hiçbir flush argüman:

>>> 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.

Alt Python sürümlerinden meraklı geçiş için: __future__sürüm, flush"Python 3.3'e deşarj
Oliver

69

Ayrıca bu blogda önerildiği gibi sys.stdout, arabelleksiz modda yeniden açılabilir :

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

Her biri stdout.writeve printişlem daha sonra otomatik olarak yıkanacaktır.


2
Ubuntu 12.04 python 2.7'de bu bana verirUnsupportedOperation: IOStream has no fileno.
drevicko

3
Hata! Python 3 öğrendi. Bu kod parçasını yürütmeme izin vermiyor!
EKons

Bu deyimle kafam karıştı. Bunu yaptıktan sonra, her ikisi de dosyaya "sahip" olduğunu düşündüğü iki Dosya benzeri nesne (orijinal sys.stdout ve yeni sys.stdout) yok mu? Bu kötü, değil mi?
Don Hatch

62

Python 3.x ile print()fonksiyon genişletildi:

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

Yani, şunları yapabilirsiniz:

print("Visiting toilet", flush=True)

Python Doküman Girişi


36

Kullanılması -ukomut satırı anahtarını çalışır, ancak biraz hantaldır. Bu, kullanıcı komut dosyası -useçeneği olmadan çağırırsa programın yanlış davranacağı anlamına gelir . Genellikle stdoutböyle bir özel kullanın :

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)

... Şimdi hepsi senin print ( sys.stdoutörtülü olarak kullanan ) çağrılarınız otomatik olarak flushdüzenlenecektir.


4
Ben dosyadan devralma ve sonra ekleyerek stdout için temsilci seçmenizi öneririz. def __getattr__(self,name): return object.__getattribute__(self.f, name)
deaththreetimes

2
@Diedthreetimes yorum tarafından önerilen değişiklikler olmadan, "ValueError: kapalı dosya üzerinde G / Ç işlemi"
blueFast

19

Neden arabelleksiz bir dosya kullanmayı denemiyorsunuz?

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

VEYA

sys.stdout = open('out.log', 'a', 0)

1
Tamponlanmamış bir dosya oluşturmasını istemiyor; mevcut stdout'u (konsola, terminale veya herhangi bir şeye yönlendirilir: bu değiştirilmemelidir) arabelleksiz yapmak istiyor.
maviFast

13

Dan'ın fikri pek işe yaramıyor:

#!/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"

Sonuç:

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

Sorunun aslında gerekli olmayan dosya sınıfından miras olduğuna inanıyorum. Sys.stdout için dokümanlara göre:

stdout ve stderr'in yerleşik dosya nesneleri olması gerekmez: dize argümanı alan bir write () yöntemine sahip olduğu sürece herhangi bir nesne kabul edilebilir.

çok değişiyor

class flushfile(file):

için

class flushfile(object):

iyi çalışmasını sağlar.


17
Oy yok çünkü bu IS @ Dan'ın çözümü ... (Çözümünü kopyalamak yerine Dan'ın gönderisini yorumlamalısınız)
gecco

8

İşte writelines () ve fileno () sağlayan sürümüm:

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

Üstün çözüm. Ve çalışıyor. Python 3.4.0 üzerinde test edilmiştir. Kaynaklanan diğer sürümlerde filebir hata alıyorum. fileSınıf yok .
Colin D Bennett

6

Python 3'te varsayılan olarak şu şekilde ayarlanmış olarak yazdırma işlevinin üzerine yazabilirsiniz: flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)

2
diğer yüksek kaliteli yanıtlar göz önüne alındığında bu cevap biraz ışık gibi görünüyor. biraz daha eklemek isteyebilirsiniz.
Noktalı virgüller ve Koli bandı

5

Python 3.4'te böyle yaptım:

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

2

Önce yıkama seçeneğinin nasıl çalıştığını anlamak için mücadele ettim. Bir 'yükleme ekranı' yapmak istedim ve işte bulduğum çözüm:

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

İlk satır önceki baskıyı temizler ve ikinci satır yeni bir güncellenmiş mesaj yazdırır. Burada tek satırlık bir sözdizimi olup olmadığını bilmiyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.