Come svuotare l'output della funzione di stampa?


1216

Come imposto la funzione di stampa di Python per l'output sullo schermo?

Questo non è un duplicato di Disabilita buffering dell'output : la domanda collegata sta tentando un output senza buffer, mentre questo è più generale. Le risposte migliori a questa domanda sono troppo potenti o coinvolte per questa (non sono buone risposte per questo), e questa domanda può essere trovata su Google da un neofita relativo.

Risposte:


1428

Su Python 3, printpuò accettare un flushargomento facoltativo

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

Su Python 2 dovrai farlo

import sys
sys.stdout.flush()

dopo aver chiamato print. Per impostazione predefinita, printstampa su sys.stdout(vedere la documentazione per ulteriori informazioni sugli oggetti file ).


347

In esecuzione python -h, vedo un'opzione della riga di comando :

-u: stdout binario senza buffer e stderr; anche PYTHONUNBUFFERED = x vedere la pagina man per i dettagli sul buffering interno relativo a '-u'

Ecco il documento pertinente .


320

Da Python 3.3, puoi forzare lo print()svuotamento della normale funzione senza la necessità di utilizzarla sys.stdout.flush(); basta impostare l'argomento della parola chiave "flush" su true. Dalla documentazione :

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

Stampa gli oggetti nel file di flusso, separati da sep e seguiti da end. sep, end e file, se presenti, devono essere indicati come argomenti di parole chiave.

Tutti gli argomenti non di parole chiave vengono convertiti in stringhe come str () e scritti nello stream, separati da sep e seguiti da end. Sia sep che end devono essere stringhe; possono anche essere Nessuno, il che significa utilizzare i valori predefiniti. Se non viene fornito alcun oggetto, print () scriverà solo end.

L'argomento file deve essere un oggetto con un metodo write (stringa); se non è presente o Nessuno, verrà utilizzato sys.stdout. Se l'output è bufferizzato di solito viene determinato dal file, ma se l'argomento della parola chiave flush è vero, il flusso viene scaricato forzatamente.


198

Come svuotare l'output della stampa Python?

Suggerisco cinque modi per farlo:

  • In Python 3, chiama print(..., flush=True)(l'argomento flush non è disponibile nella funzione di stampa di Python 2 e non esiste un analogo per l'istruzione print).
  • Richiamare file.flush()il file di output (per fare ciò possiamo avvolgere la funzione di stampa di python 2), ad esempio,sys.stdout
  • applicarlo a ogni chiamata della funzione di stampa nel modulo con una funzione parziale,
    print = partial(print, flush=True)applicata al modulo globale.
  • applicare questo al processo con un flag ( -u) passato al comando interprete
  • applicalo a ogni processo Python nel tuo ambiente con PYTHONUNBUFFERED=TRUE(e disattiva la variabile per annullare ciò).

Python 3.3+

Usando Python 3.3 o versioni successive, puoi semplicemente fornire flush=Truecome argomento una parola chiave alla printfunzione:

print('foo', flush=True) 

Python 2 (o <3.3)

Non hanno eseguito il backport flushdell'argomento su Python 2.7 Quindi, se si utilizza Python 2 (o meno di 3.3) e si desidera un codice compatibile con 2 e 3, posso suggerire il seguente codice di compatibilità. (Nota che l' __future__importazione deve essere in / molto "vicino alla parte superiore del modulo "):

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

Il codice di compatibilità di cui sopra coprirà la maggior parte degli usi, ma per un trattamento molto più approfondito, consultare il sixmodulo .

In alternativa, puoi semplicemente chiamare file.flush()dopo la stampa, ad esempio, con l'istruzione print in Python 2:

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

Modifica del valore predefinito in un modulo in flush=True

È possibile modificare il valore predefinito per la funzione di stampa utilizzando functools.partial nell'ambito globale di un modulo:

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

se guardi la nostra nuova funzione parziale, almeno in Python 3:

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

Possiamo vedere che funziona come al solito:

>>> print('foo')
foo

E possiamo effettivamente sostituire il nuovo predefinito:

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

Nota di nuovo, questo cambia solo l'ambito globale corrente, perché il nome di stampa sull'ambito globale corrente oscurerà la printfunzione incorporata (o annullerà il riferimento alla funzione di compatibilità, se ne usi una in Python 2, in quell'ambito globale corrente).

Se vuoi farlo all'interno di una funzione anziché nell'ambito globale di un modulo, dovresti dargli un nome diverso, ad esempio:

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

Se lo dichiarate globale in una funzione, lo state cambiando nello spazio dei nomi globale del modulo, quindi dovreste semplicemente inserirlo nello spazio dei nomi globale, a meno che quel comportamento specifico sia esattamente quello che volete.

Modifica del valore predefinito per il processo

Penso che l'opzione migliore qui sia usare la -ubandiera per ottenere un output senza buffer.

$ python -u script.py

o

$ python -um package.module

Dai documenti :

Forza lo stdin, lo stdout e lo stderr ad essere totalmente senza buffer. Sui sistemi in cui è importante, metti anche stdin, stdout e stderr in modalità binaria.

Si noti che esiste un buffering interno in file.readlines () e Oggetti file (per la riga in sys.stdin) che non è influenzato da questa opzione. Per ovviare a questo, ti consigliamo di utilizzare file.readline () all'interno di un ciclo while 1:.

Modifica del valore predefinito per l'ambiente operativo della shell

È possibile ottenere questo comportamento per tutti i processi Python nell'ambiente o negli ambienti che ereditano dall'ambiente se si imposta la variabile di ambiente su una stringa non vuota:

ad esempio, in Linux o OSX:

$ export PYTHONUNBUFFERED=TRUE

o Windows:

C:\SET PYTHONUNBUFFERED=TRUE

dai documenti :

PYTHONUNBUFFERED

Se è impostato su una stringa non vuota, equivale a specificare l'opzione -u.


appendice

Ecco la guida sulla funzione di stampa da Python 2.7.12 - Si noti che non v'è alcun flush argomento:

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

Per i curiosi migratori dalle versioni inferiori di Python: la __future__versione non include flushperché "l'argomento flush è stato aggiunto in Python 3.3 (dopo che print () è stato riportato in 2.7 tramite un'importazione futura)" bugs.python.org/issue28458
Oliver

69

Inoltre, come suggerito in questo blog, è possibile riaprire sys.stdoutin modalità senza buffer:

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

Ogni stdout.writee printil funzionamento sarà lavato automaticamente in seguito.


2
Su Ubuntu 12.04 in Python 2.7 questo mi dàUnsupportedOperation: IOStream has no fileno.
drevicko,

3
Whoops, Python 3 lo ha scoperto. Non mi permetterà di eseguire questo pezzo di codice!
EKons

Sono confuso da questo idioma. Dopo aver fatto questo, non ci sono ora due oggetti simili a File (l'originale sys.stdout e il nuovo sys.stdout) che entrambi pensano di "possedere" il fileno? È male, vero?
Don Hatch,

62

Con Python 3.x la print()funzione è stata estesa:

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

Quindi, puoi semplicemente fare:

print("Visiting toilet", flush=True)

Voce di Python Docs


36

L'uso dell'opzione della -uriga di comando funziona, ma è un po 'goffo. Significherebbe che il programma potrebbe comportarsi in modo errato se l'utente invocasse lo script senza l' -uopzione. Di solito uso un costume stdout, come questo:

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)

... Ora tutte le tue printchiamate (che usano sys.stdoutimplicitamente), verranno automaticamente modificate flush.


4
Consiglio di non ereditare dal file e quindi delegare a stdout aggiungendo. def __getattr__(self,name): return object.__getattribute__(self.f, name)
diethreetimes il

2
Senza le modifiche suggerite dal commento di @diedthreetimes, ottengo "ValueError: operazione I / O su file chiuso"
blueFast

19

Perché non provare a utilizzare un file senza buffer?

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

O

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

1
Non vuole creare un file senza buffer; vuole rendere senza buffer lo stdout esistente (reindirizzato alla console, al terminale o altro: questo non deve essere modificato).
blueFast,

13

L'idea di Dan non funziona del tutto:

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

Il risultato:

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

Credo che il problema sia che eredita dalla classe del file, che in realtà non è necessario. Secondo i documenti per sys.stdout:

stdout e stderr non devono necessariamente essere oggetti file incorporati: qualsiasi oggetto è accettabile purché abbia un metodo write () che accetta un argomento stringa.

così cambiando

class flushfile(file):

per

class flushfile(object):

lo fa funzionare bene.


17
Nessun voto perché questa è la soluzione di Dan @ ... (dovresti piuttosto commentare il post di Dan invece di copiare la sua soluzione)
gecco

8

Ecco la mia versione, che fornisce anche writelines () e 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()

Soluzione superiore. E funziona Testato su Python 3.4.0. Con le altre versioni, da cui deriva file, ricevo un errore. Non c'è filelezione.
Colin D Bennett,

6

In Python 3 è possibile sovrascrivere la funzione di stampa con l'impostazione predefinita su 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
questa risposta sembra un po 'leggera, date tutte le altre risposte di alta qualità. potresti voler aggiungere un po 'di più ad esso.
Punto e virgola e nastro adesivo

5

L'ho fatto così in Python 3.4:

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

2

Ho prima faticato a capire come funzionava l'opzione flush. Volevo fare una 'schermata di caricamento' ed ecco la soluzione che ho trovato:

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

La prima riga elimina la stampa precedente e la seconda riga stampa un nuovo messaggio aggiornato. Non so se esiste una sintassi di una riga qui.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.