Как очистить вывод функции печати?

1218

Как заставить функцию печати Python выводить на экран?

Это не дубликат буферизации вывода данных - связанный вопрос пытается получить небуферизованный вывод, хотя это более общий вопрос. Лучшие ответы на этот вопрос слишком сильны или вовлечены для этого (они не являются хорошими ответами для этого), и этот вопрос может быть найден в Google относительным новичком.

Вальтер Ниссен
источник

Ответы:

1430

На Python 3 printможет принимать необязательный flushаргумент

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

На Python 2 вам придется сделать

import sys
sys.stdout.flush()

после звонка print. По умолчанию printпечатает в sys.stdout(см. Документацию для получения дополнительной информации о файловых объектах ).

CesarB
источник
347

Запустив python -h, я вижу параметр командной строки :

-u: небуферизованные двоичные stdout и stderr; также PYTHONUNBUFFERED = x см. справочную страницу для деталей о внутренней буферизации, связанной с '-u'

Вот соответствующий документ .

гимель
источник
321

Начиная с Python 3.3, вы можете принудительно сбросить обычную print()функцию без необходимости ее использования sys.stdout.flush(); просто установите для аргумента ключевого слова "flush" значение true. Из документации :

print (* объекты, sep = '', end = '\ n', file = sys.stdout, flush = False)

Распечатать объекты в файл потока, разделенные sep и последующим end. sep, end и file, если они есть, должны быть заданы в качестве аргументов ключевых слов.

Все аргументы, не являющиеся ключевыми словами, преобразуются в строки, как это делает str (), и записываются в поток, разделяются sep и сопровождаются end. И sep, и end должны быть строками; они также могут быть None, что означает использование значений по умолчанию. Если объекты не указаны, print () просто напишет end.

Аргумент файла должен быть объектом с методом write (string); если он отсутствует или отсутствует, будет использоваться sys.stdout. Будь буферизован вывод, обычно определяется файлом, но если аргумент ключевого слова flush равен true, поток принудительно очищается.

Евгений Саджин
источник
199

Как очистить вывод печати Python?

Я предлагаю пять способов сделать это:

  • В Python 3 вызывается print(..., flush=True)(аргумент flush недоступен в функции печати Python 2, и аналога для оператора print нет).
  • Вызовите file.flush()выходной файл (для этого мы можем обернуть функцию печати Python 2), например,sys.stdout
  • примените это к каждому вызову функции печати в модуле с частичной функцией,
    print = partial(print, flush=True)примененной к модулю global.
  • применить это к процессу с помощью flag ( -u), переданного команде интерпретатора
  • примените это к каждому процессу python в вашей среде с помощью PYTHONUNBUFFERED=TRUE(и сбросьте переменную, чтобы отменить это).

Python 3.3+

Используя Python 3.3 или выше, вы можете просто предоставить flush=Trueв качестве ключевого аргумента printфункцию:

print('foo', flush=True) 

Python 2 (или <3.3)

Они не перенесли flushаргумент в Python 2.7. Поэтому, если вы используете Python 2 (или менее 3.3) и хотите получить код, совместимый как с 2, так и с 3, могу ли я предложить следующий код совместимости. (Обратите внимание, что __future__импорт должен быть в / очень "в верхней части вашего модуля "):

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

Приведенный выше код совместимости будет охватывать большинство применений, но для более тщательного рассмотрения см. sixМодуль .

В качестве альтернативы, вы можете просто вызвать file.flush()после печати, например, оператор print в Python 2:

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

Изменение значения по умолчанию в одном модуле на flush=True

Вы можете изменить значение по умолчанию для функции печати, используя functools.partial в глобальной области видимости модуля:

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

если вы посмотрите на нашу новую частичную функцию, по крайней мере, в Python 3:

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

Мы видим, что это работает как обычно:

>>> print('foo')
foo

И мы можем переопределить новое значение по умолчанию:

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

Обратите внимание, что это только меняет текущую глобальную область, потому что имя печати в текущей глобальной области будет затенять встроенную printфункцию (или разыменовать функцию совместимости, если она используется в Python 2, в этой текущей глобальной области).

Если вы хотите сделать это внутри функции, а не в глобальной области видимости модуля, вы должны дать ему другое имя, например:

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

Если вы объявляете его глобальным в функции, вы изменяете его в глобальном пространстве имен модуля, поэтому вы должны просто поместить его в глобальное пространство имен, если только это конкретное поведение не является именно тем, что вам нужно.

Изменение значения по умолчанию для процесса

Я думаю, что лучшим вариантом здесь является использование -uфлага для получения небуферизованного вывода.

$ python -u script.py

или

$ python -um package.module

Из документов :

Заставьте stdin, stdout и stderr быть полностью небуферизованными. В системах, где это имеет значение, также установите stdin, stdout и stderr в двоичном режиме.

Обратите внимание, что в file.readlines () и File Objects (для строки в sys.stdin) есть внутренняя буферизация, на которую не влияет эта опция. Чтобы обойти это, вы захотите использовать file.readline () внутри цикла while 1 :.

Изменение значения по умолчанию для операционной среды оболочки

Вы можете получить это поведение для всех процессов Python в среде или средах, которые наследуются от среды, если для переменной среды задать непустую строку:

например, в Linux или OSX:

$ export PYTHONUNBUFFERED=TRUE

или Windows:

C:\SET PYTHONUNBUFFERED=TRUE

из документов :

PYTHONUNBUFFERED

Если для этого параметра задана непустая строка, это эквивалентно указанию опции -u.


добавление

Вот справка по функции печати из Python 2.7.12 - обратите внимание, что аргументов нет flush :

>>> 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.
Аарон Холл
источник
Для любопытной миграции с более низких версий Python: __future__версия не включает, flushпотому что «аргумент flush был добавлен в Python 3.3 (после того, как print () был перенесен в 2.7 через будущий импорт)» bugs.python.org/issue28458
Оливер
69

Также, как предлагается в этом блоге, можно открыть sys.stdoutв небуферизованном режиме:

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

Каждая stdout.writeи printоперация будет автоматически покраснел потом.

Энтони Хэтчкинс
источник
2
На Ubuntu 12.04 в python 2.7 это дает мнеUnsupportedOperation: IOStream has no fileno.
drevicko
3
Ой, Python 3 узнал. Это не позволит мне выполнить этот кусок кода!
EKons
Я смущен этой идиомой. После того, как вы это сделаете, не появятся ли сейчас два File-like объекта (исходный sys.stdout и новый sys.stdout), которые оба думают, что они "владеют" fileno? Это плохо, правда?
Дон Хэтч
62

В Python 3.x print()функция была расширена:

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

Итак, вы можете просто сделать:

print("Visiting toilet", flush=True)

Python Docs Entry

Ной Крассер
источник
36

Использование -uключа командной строки работает, но это немного неуклюже. Это означало бы, что программа могла бы вести себя некорректно, если бы пользователь вызывал скрипт без -uопции. Я обычно использую обычай stdout, как это:

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)

... Теперь все ваши printзвонки (которые используют sys.stdoutнеявно) будут автоматически flushредактироваться.

Дэн Ленски
источник
4
Я рекомендую не наследовать от файла, а затем делегировать на стандартный вывод путем добавления. def __getattr__(self,name): return object.__getattribute__(self.f, name)
умер трижды
2
Без изменений, предложенных комментарием @diedthreetimes, я получаю «ValueError: операция ввода-вывода для закрытого файла»
blueFast,
19

Почему бы не попробовать использовать небуферизованный файл?

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

ИЛИ

sys.stdout = open('out.log', 'a', 0)
Nakilon
источник
1
Он не хочет создавать небуферизованный файл; он хочет сделать существующий стандартный вывод (перенаправленный на консоль, терминал или что-то еще: это не должно быть изменено) не буферизованным.
BlueFast
13

Идея Дэна не совсем работает:

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

Результат:

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

Я считаю, что проблема в том, что он наследуется от класса файла, что на самом деле не нужно. В соответствии с документами для sys.stdout:

stdout и stderr не обязательно должны быть встроенными файловыми объектами: любой объект приемлем, если у него есть метод write (), который принимает строковый аргумент.

так меняется

class flushfile(file):

в

class flushfile(object):

заставляет это работать просто отлично.

Камил Кисиэль
источник
17
Нет голосования, потому что это решение IS @ Dan ... (Вы скорее должны прокомментировать сообщение Дэна вместо того, чтобы копировать его решение)
gecco
8

Вот моя версия, которая также предоставляет writelines () и 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
источник
Превосходное решение. И это работает. Протестировано на Python 3.4.0. С другими версиями, которые являются производными file, я получаю сообщение об ошибке. Там нет fileкласса.
Колин Д. Беннетт
6

В Python 3 вы можете перезаписать функцию печати со значением по умолчанию flush = True

def print(*objects, sep=' ', end='\n', file=sys.stdout, flush=True):
    __builtins__.print(*objects, sep=sep, end=end, file=file, flush=flush)
user263387
источник
2
этот ответ кажется немного легким, учитывая все другие высококачественные ответы. Вы можете добавить немного больше к этому.
Точка с запятой и клейкая лента
5

Я сделал это так в 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
источник
2

Сначала я пытался понять, как работает опция сброса. Я хотел сделать «отображение загрузки», и вот решение, которое я нашел:

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

Первая строка сбрасывает предыдущую печать, а вторая строка печатает новое обновленное сообщение. Я не знаю, существует ли здесь однострочный синтаксис.

Гийом Мужо
источник