Как заставить функцию печати Python выводить на экран?
This is not a duplicate of Disable output buffering - the linked question is attempting unbuffered output, while this is more general. The top answers in that question are too powerful or involved for this one (they're not good answers for this), and this question can be found on Google by a relative newbie.
В Python 3 print
может принимать необязательный аргумент flush
print("Hello world!", flush=True)
На Python 2 вам нужно будет сделать
import sys
sys.stdout.flush()
после звонка print
. По умолчанию print
печатает в sys.stdout
(дополнительные сведения о файловые объекты см. В документации).
Запустив python -h
, я вижу параметр командной строки:
-u : unbuffered binary stdout and stderr; also PYTHONUNBUFFERED=x see man page for details on internal buffering relating to '-u'
Использование переключателя командной строки -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
.
Я рекомендую не наследовать от файла, а затем делегировать его на стандартный вывод, добавляя. def __getattr__(self,name): return object.__getattribute__(self.f, name)
Без изменений, предложенных комментарием @diedthreetimes, я получаю «ValueError: операция ввода-вывода в закрытом файле»
Идея Дэна не совсем работает:
#!/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 and stderr needn’t be built-in file objects: any object is acceptable as long as it has a write() method that takes a string argument.
так меняется
class flushfile(file):
к
class flushfile(object):
заставляет его работать нормально.
Нет голоса, потому что это решение IS @ Dan ... (вам лучше прокомментировать сообщение Дэна, а не копировать его решение)
Почему бы не попробовать использовать небуферизованный файл?
f = open('xyz.log', 'a', 0)
ИЛИ ЖЕ
sys.stdout = open('out.log', 'a', 0)
Он не хочет создавать небуферизованный файл; он хочет сделать существующий стандартный вывод (перенаправленный на консоль, терминал или что-то еще: это не должно быть изменено) небуферизованным.
Вот моя версия, в которой также есть 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()
Превосходное решение. И это работает. Проверено на Python 3.4.0. С другими версиями, производными от file
, я получаю сообщение об ошибке. Класса file
нет.
Также, как предлагается в этот блог, можно повторно открыть sys.stdout
в небуферизованном режиме:
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
После этого каждая операция stdout.write
и print
будет автоматически сбрасываться.
В Ubuntu 12.04 в python 2.7 это дает мне UnsupportedOperation: IOStream has no fileno.
Упс, Python 3 обнаружил. Это не позволит мне выполнить этот фрагмент кода!
Меня смущает эта идиома. После того, как вы это сделаете, разве не осталось двух объектов типа File (исходный sys.stdout и новый sys.stdout), которые оба думают, что они «владеют» файлом? Это плохо, правда?
Начиная с Python 3.3, вы можете принудительно сбросить обычную функцию print()
без использования sys.stdout.flush()
; просто установите для аргумента ключевого слова "flush" значение true. От документация:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
Print objects to the stream file, separated by sep and followed by end. sep, end and file, if present, must be given as keyword arguments.
All non-keyword arguments are converted to strings like str() does and written to the stream, separated by sep and followed by end. Both sep and end must be strings; they can also be None, which means to use the default values. If no objects are given, print() will just write end.
The file argument must be an object with a write(string) method; if it is not present or None, sys.stdout will be used. Whether output is buffered is usually determined by file, but if the flush keyword argument is true, the stream is forcibly flushed.
Я сделал это так в Python 3.4:
'''To write to screen in real-time'''
message = lambda x: print(x, flush=True, end = "")
message('I am flushing out now...')
В Python 3.x функция print()
была расширена:
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
Итак, вы можете просто сделать:
print("Visiting toilet", flush=True)
How to flush output of Python print?
Я предлагаю пять способов сделать это:
print(..., flush=True)
(аргумент flush недоступен в функции печати Python 2, и нет аналога для оператора печати).file.flush()
в выходном файле (для этого мы можем обернуть функцию печати Python 2), например sys.stdout
print = partial(print, flush=True)
применяется к модулю global.-u
), переданным команде интерпретатораPYTHONUNBUFFERED=TRUE
(и отключите переменную, чтобы отменить это).Используя Python 3.3 или выше, вы можете просто указать flush=True
в качестве аргумента ключевого слова функции print
:
print('foo', flush=True)
Они не перенесли аргумент 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()
после печати, например, с помощью оператора печати в 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
Из документы:
Force stdin, stdout and stderr to be totally unbuffered. On systems where it matters, also put stdin, stdout and stderr in binary mode.
Note that there is internal buffering in file.readlines() and File Objects (for line in sys.stdin) which is not influenced by this option. To work around this, you will want to use file.readline() inside a while 1: loop.
Вы можете получить такое поведение для всех процессов python в среде или средах, которые наследуются от среды, если вы установите для переменной среды непустую строку:
например, в Linux или OSX:
$ export PYTHONUNBUFFERED=TRUE
или Windows:
C:\SET PYTHONUNBUFFERED=TRUE
из документы:
PYTHONUNBUFFERED
If this is set to a non-empty string it is equivalent to specifying the -u option.
Вот справка по функции печати из 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
Это должен быть принятый ответ. Предоставляет обходные пути и много информации.
В 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)
этот ответ кажется немного легким с учетом всех остальных качественных ответов. вы можете добавить к нему немного больше.
Сначала я изо всех сил пытался понять, как работает опция промывки. Я хотел сделать «отображение загрузки», и вот решение, которое я нашел:
for i in range(100000):
print('{:s}\r'.format(''), end='', flush=True)
print('Loading index: {:d}/100000'.format(i+1), end='')
Первая строка сбрасывает предыдущий отпечаток, а вторая строка - новое обновленное сообщение. Я не знаю, существует ли здесь однострочный синтаксис.
Если вы используете его на платформе Linux / Unix, вы можете добавить
-u
в командную строку интерпретатора (первая строка файла сценария), поэтому измените первую строку с (что-то вроде)#!/usr/bin/python3
на#!/usr/bin/python3 -u
- теперь, когда вы запустите свой скрипт (например,./my_script.py
)-u
всегда будет добавлен за вас