Проблема с новой строкой в ​​контекстном менеджере Python

Используя contextmanager Python, я хочу создать оболочку для отображения Linux- как прогресс определенного блока кода:

Doing something... done. [42 ms]

Это работает - вроде:

from contextlib import contextmanager
import time

@contextmanager
def msg(m):
    print(m + "... ", end='')
    t_start = time.time()
    yield
    t_duration_ms = 1000 * (time.time() - t_start)
    print("done. [{:.0f} ms]".format(t_duration_ms))

В этом примере использования следует напечатать "Doing something..." без разрыва строки, подождать секунду, напечатать "done. [1000 мс]", включая разрыв строки и покидать.

with msg("Doing something"):
    time.sleep(1)

Однако при запуске фрагмента вывод сначала ожидает секунду, а после печатается вся строка. При удалении end='' в первом операторе print() все работает, как и ожидалось, но за счет уродливого вывода.

Почему это так, так задумано и что можно сделать, чтобы избежать такого поведения?

(Python 3.4.0 в Linux Mint 17.1)


person Finwood    schedule 14.06.2015    source источник


Ответы (1)


Проблема, вероятно, связана с буферизацией stdout. Вам нужно вручную очистить его, чтобы сообщение отображалось. В Python 3.3+ функция print имеет аргумент flush:

from contextlib import contextmanager
import time

@contextmanager
def msg(m):
    print(m + "... ", end='', flush=True)
    t_start = time.time()
    yield
    t_duration_ms = 1000 * (time.time() - t_start)
    print("done. [{:.0f} ms]".format(t_duration_ms))

До версии 3.3 вам приходилось использовать метод flush из stdout:

print(m + "... ", end='')
sys.stdout.flush()
person Lev Levitsky    schedule 14.06.2015