Вопрос по python – Отключить буферизацию вывода

442

Включена ли буферизация вывода по умолчанию в интерпретаторе Python дляsys.stdout?

Если ответ положительный, какие есть способы его отключения?

Предложения на данный момент:

Use the -u command line switch Wrap sys.stdout in an object that flushes after every write Set PYTHONUNBUFFERED env var sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

Есть ли другой способ установить глобальный флаг вsys/sys.stdout программно во время исполнения?

Для `print & apos; в Python 3 см.this answer. Antti Haapala
Я думаю, что недостаток-u является то, что он не будет работать для скомпилированного байт-кода или для приложений с__main__.py файл в качестве точки входа. akhan

Ваш Ответ

16   ответов
3

(Я разместил комментарий, но он как-то потерялся.

As I noticed, CPython (at least on Linux) behaves differently depending on where the output goes. If it goes to a tty, then the output is flushed after each '\n'
If it goes to a pipe/process, then it is buffered and you can use the flush() based solutions or the -u option recommended above.

Slightly related to output buffering:
If you iterate over the lines in the input with

for line in sys.stdin:
...

тогдаfor реализация вCPython некоторое время будет собирать входные данные, а затем выполнять тело цикла для набора входных строк. Если ваш сценарий собирается записывать выходные данные для каждой входной строки, это может выглядеть как буферизация выходных данных, но на самом деле он пакетный, и, следовательно, ни один изflush()и т.д. методы помогут этому. Интересно, что у вас нет такого поведения вpypy. To avoid this, you can use

while True: line=sys.stdin.readline()
...

here's your commentError: User Rate Limit Exceededfor line in sys.stdinError: User Rate Limit Exceededfor line in iter(sys.stdin.readline, "")
Error: User Rate Limit Exceeded
3

ту.

fl = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL)
fl |= os.O_SYNC # or os.O_DSYNC (if you don't care the file timestamp updates)
fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, fl)
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededstackoverflow.com/questions/881696/…
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded Eli Bendersky
12
def disable_stdout_buffering():
    # Appending to gc.garbage is a way to stop an object from being
    # destroyed.  If the old sys.stdout is ever collected, it will
    # close() stdout, which is not good.
    gc.garbage.append(sys.stdout)
    sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

# Then this will give output in the correct order:
disable_stdout_buffering()
print "hello"
subprocess.call(["echo", "bye"])

тся idempotent, и множественные вызовы приведут к ошибке, подобной этой:

Traceback (most recent call last):
  File "test/buffering.py", line 17, in <module>
    print "hello"
IOError: [Errno 9] Bad file descriptor
close failed: [Errno 9] Bad file descriptor

Другая возможность:

def disable_stdout_buffering():
    fileno = sys.stdout.fileno()
    temp_fd = os.dup(fileno)
    sys.stdout.close()
    os.dup2(temp_fd, fileno)
    os.close(temp_fd)
    sys.stdout = os.fdopen(fileno, "w", 0)

(Присоединение к gc.garbage не является такой хорошей идеей, потому что это место, где создаются неразрушимые циклы, и вы можете проверить их.)

Error: User Rate Limit Exceededstdout все еще живет наsys.__stdout__Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededValueError: can't have unbuffered text I/OError: User Rate Limit Exceededprint().
Error: User Rate Limit Exceededstackoverflow.com/questions/23440216/…
1

sys.stderr вместоsys.stdout или просто позвонитьsys.stdout.flush() явно заставить запись произойти.

Вы можете легко перенаправить все напечатанное, выполнив:

import sys; sys.stdout = sys.stderr
print "Hello World!"

Или перенаправить только для конкретногоprint заявление:

print >>sys.stderr, "Hello World!"

Чтобы сбросить стандартный вывод, вы можете просто сделать:

sys.stdout = sys.__stdout__
Error: User Rate Limit ExceededstdoutError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
78

Как очистить вывод печати Python? или вФункция печати Python, которая очищает буфер, когда он вызывается?, но поскольку они были помечены как дубликаты этого (что я не согласен), я отвечу на это здесь.

Начиная с Python 3.3 print () поддерживает ключевое слово аргумент & quot; flush & quot; (см документацию):

print('Hello World!', flush=True)
12

но я пока не могу комментировать.

Прямой способ использованияflush Ключевой аргументPython 3 чтобыalways иметь небуферизованный вывод:

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

после этого печать всегда сбрасывает вывод напрямую (кромеflush=False дано).

Отметьте (а), что это отвечает на вопрос только частично, поскольку оно не перенаправляет весь вывод. Но я думаюprint является наиболее распространенным способом создания выходных данных дляstdout/stderr в Python, так что эти 2 строки охватывают, вероятно, большинство случаев использования.

Обратите внимание (б), что он работает только в модуле / скрипте, где вы его определили. Это может быть полезно при написании модуля, так как он не портитsys.stdout.

Python 2 не обеспечиваетflush аргумент, но вы могли бы подражать Python 3-типаprint функционировать как описано здесьhttps://stackoverflow.com/a/27991478/3734258 .

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededflushError: User Rate Limit Exceeded
6

stdbuf полезность:

stdbuf -oL python <script>

3

python 2.7, ipython 0.12), затем вызывается впоследствии (несколько раз):

def DisOutBuffering():
    if sys.stdout.name == '<stdout>':
        sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

    if sys.stderr.name == '<stderr>':
        sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 0)
Error: User Rate Limit Exceededsys.stdout is sys.__stdout__Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
371

Магнус Лыцка ответ по списку рассылки:

You can skip buffering for a whole python process using "python -u" (or#!/usr/bin/env python -u etc) or by setting the environment variable PYTHONUNBUFFERED.

You could also replace sys.stdout with some other stream like wrapper which does a flush after every call.

class Unbuffered(object):
   def __init__(self, stream):
       self.stream = stream
   def write(self, data):
       self.stream.write(data)
       self.stream.flush()
   def writelines(self, datas):
       self.stream.writelines(datas)
       self.stream.flush()
   def __getattr__(self, attr):
       return getattr(self.stream, attr)

import sys
sys.stdout = Unbuffered(sys.stdout)
print 'Hello'
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceedediter()Error: User Rate Limit ExceededwhileError: User Rate Limit Exceededfor line in iter(pipe.readline, ''):Error: User Rate Limit Exceededfor line in pipe:Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded\nError: User Rate Limit Exceededfor line in sys.stdin:Error: User Rate Limit Exceededwhile true: line = sys.stdin.readline()
#!/usr/bin/env python -uError: User Rate Limit Exceededhere
__getattr__Error: User Rate Limit Exceeded
46

Вы можете отключить его в командной строке с помощью & quot; -u & quot; переключатель.

В качестве альтернативы вы можете вызывать .flush, () для sys.stdout при каждой записи (или обернуть его объектом, который делает это автоматически)

3

only write методsys.stdout с тем, который звонитflush, Предлагаемый способ реализации приведен ниже.

def write_flush(args, w=stdout.write):
    w(args)
    stdout.flush()

Значение по умолчаниюw аргумент будет оставаться оригинальнымwrite ссылка на метод.After write_flush определяется, оригиналwrite может быть отменено

stdout.write = write_flush

Код предполагает, чтоstdout импортируется таким образомfrom sys import stdout.

72
# reopen stdout file descriptor with write mode
# and 0 as the buffer size (unbuffered)
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)

3rd Party EDIT

Unsupported in recent versions of Python 3

@ Сорин: Я понимаю вашу точку зрения. Я тестировал с намерением вывести двоичный файл.
На Python 3 приведенная выше строка выдаст исключение:ValueError: can't have unbuffered text I/O.
@meawoppl: вы могли бы пройтиflush=True параметр дляprint() Функция начиная с Python 3.3.
@ Сорин: Да, это так. Пожалуйста, объясните вашу претензию.
Это больше не работает в Python 3, см. PEP 3116.
10

он включен по умолчанию. Вы можете отключить его, используя опцию -u в командной строке при вызове python.

2

stdout.

import sys 
myFile= open( "a.log", "w", 0 ) 
sys.stdout= myFile

Вы не можете волшебным образом изменить предоставляемый системой стандартный вывод; так как он поставляется вашей программой на Python операционной системой.

11

import os
import sys
buf_arg = 0
if sys.version_info[0] == 3:
    os.environ['PYTHONUNBUFFERED'] = '1'
    buf_arg = 1
sys.stdout = os.fdopen(sys.stdout.fileno(), 'a+', buf_arg)
sys.stderr = os.fdopen(sys.stderr.fileno(), 'a+', buf_arg)
@MichaelClerx Ммм хм, всегда не забывайте закрывать свои файлы xD.
Запустите это дважды, и оно вылетит на Windows :-)
1

чтобы всегда отправлять flush = True:

_orig_print = print

def print(*args, **kwargs):
    _orig_print(*args, flush=True, **kwargs)

Похожие вопросы