Перенаправление stdout на "ничто" в python
У меня большой проект, состоящий из достаточно большого количества модулей, каждый из которых печатает что-то на стандартный вывод. Сейчас, когда проект вырос в размерах, таких крупных нет. из print
операторы печатают много на std out, что значительно замедляет работу программы.
Итак, теперь я хочу во время выполнения решить, печатать или нет что-либо на стандартный вывод. Я не могу вносить изменения в модули, так как их много. (Я знаю, что могу перенаправить стандартный вывод в файл, но даже это значительно медленнее.)
Итак, мой вопрос, как мне перенаправить стандартный вывод, то есть, как я могу сделать print
Скажите ничего не делать?
# I want to do something like this.
sys.stdout = None # this obviously will give an error as Nonetype object does not have any write method.
В настоящее время единственная идея, которую я имею, состоит в том, чтобы создать класс, у которого есть метод записи (который ничего не делает), и перенаправить стандартный вывод в экземпляр этого класса.
class DontPrint(object):
def write(*args): pass
dp = DontPrint()
sys.stdout = dp
Есть ли в Python встроенный механизм для этого? Или есть что-то лучше этого?
15 ответов
Кросс-платформенный:
import os
import sys
f = open(os.devnull, 'w')
sys.stdout = f
В Windows:
f = open('nul', 'w')
sys.stdout = f
В Linux:
f = open('/dev/null', 'w')
sys.stdout = f
Хороший способ сделать это - создать небольшой контекстный процессор, в который вы упаковываете свои отпечатки. Затем вы просто используете его в with
Заявление, чтобы заставить замолчать весь вывод.
import os
import sys
from contextlib import contextmanager
@contextmanager
def silence_stdout():
new_target = open(os.devnull, "w")
old_target = sys.stdout
sys.stdout = new_target
try:
yield new_target
finally:
sys.stdout = old_target
with silence_stdout():
print("will not print")
print("this will print")
Выполнение этого кода выводит только вторую строку вывода, а не первую:
$ python test.py
this will print
Это работает кроссплатформенно (Windows + Linux + Mac OSX) и чище, чем другие ответы imho.
Если вы используете Python 3.4 или выше, есть простое и безопасное решение с использованием стандартной библиотеки:
import contextlib
import os
with contextlib.redirect_stdout(None):
print("This won't print!")
(по крайней мере, в моей системе) кажется, что запись в os.devnull примерно в 5 раз быстрее, чем запись в класс DontPrint, т.е.
#!/usr/bin/python
import os
import sys
import datetime
ITER = 10000000
def printlots(out, it, st="abcdefghijklmnopqrstuvwxyz1234567890"):
temp = sys.stdout
sys.stdout = out
i = 0
start_t = datetime.datetime.now()
while i < it:
print st
i = i+1
end_t = datetime.datetime.now()
sys.stdout = temp
print out, "\n took", end_t - start_t, "for", it, "iterations"
class devnull():
def write(*args):
pass
printlots(open(os.devnull, 'wb'), ITER)
printlots(devnull(), ITER)
дал следующий вывод:
<open file '/dev/null', mode 'wb' at 0x7f2b747044b0>
took 0:00:02.074853 for 10000000 iterations
<__main__.devnull instance at 0x7f2b746bae18>
took 0:00:09.933056 for 10000000 iterations
Если вы находитесь в среде Unix (включая Linux), вы можете перенаправить вывод на /dev/null
:
python myprogram.py > /dev/null
И для Windows:
python myprogram.py > nul
Как насчет этого:
from contextlib import ExitStack, redirect_stdout
import os
with ExitStack() as stack:
if should_hide_output():
null_stream = open(os.devnull, "w")
stack.enter_context(null_stream)
stack.enter_context(redirect_stdout(null_stream))
noisy_function()
При этом используются функции модуля contextlib, чтобы скрыть вывод любой команды, которую вы пытаетесь запустить, в зависимости от результата should_hide_output()
, а затем восстанавливает поведение вывода после выполнения этой функции.
Если вы хотите скрыть стандартный вывод ошибок, то импортируйте redirect_stderr
от contextlib
и добавить строку с надписью stack.enter_context(redirect_stderr(null_stream))
,
Основным недостатком является то, что это работает только в Python 3.4 и более поздних версиях.
Вы можете просто посмеяться над этим.
import mock
sys.stdout = mock.MagicMock()
Если вы не хотите иметь дело с распределением ресурсов или развертыванием собственного класса, вы можете использовать
TextIO
от набора текста Python. По умолчанию в нем есть все необходимые методы.
import sys
from typing import TextIO
sys.stdout = TextIO()
Дополнение к ответу iFreilicht - он работает как для python 2, так и для 3.
import sys
class NonWritable:
def write(self, *args, **kwargs):
pass
class StdoutIgnore:
def __enter__(self):
self.stdout_saved = sys.stdout
sys.stdout = NonWritable()
return self
def __exit__(self, *args):
sys.stdout = self.stdout_saved
with StdoutIgnore():
print("This won't print!")
sys.stdout = None
Это нормально для print()
дело. Но это может вызвать ошибку, если вы вызываете любой метод sys.stdout, например sys.stdout.write()
,
В документах есть примечание:
При некоторых условиях stdin, stdout и stderr, а также исходные значения stdin, stdout и stderr могут быть None. Обычно это относится к приложениям с графическим интерфейсом Windows, которые не подключены к консоли, а приложения Python запускаются с pythonw.
В потоке есть несколько хороших ответов, но вот мой ответ Python 3 (когда sys.stdout.fileno() больше не поддерживается):
import os
import sys
oldstdout = os.dup(1)
oldstderr = os.dup(2)
oldsysstdout = sys.stdout
oldsysstderr = sys.stderr
# Cancel all stdout outputs (will be lost) - optionally also cancel stderr
def cancel_stdout(stderr=False):
sys.stdout.flush()
devnull = open('/dev/null', 'w')
os.dup2(devnull.fileno(), 1)
sys.stdout = devnull
if stderr:
os.dup2(devnull.fileno(), 2)
sys.stderr = devnull
# Redirect all stdout outputs to a file - optionally also redirect stderr
def reroute_stdout(filepath, stderr=False):
sys.stdout.flush()
file = open(filepath, 'w')
os.dup2(file.fileno(), 1)
sys.stdout = file
if stderr:
os.dup2(file.fileno(), 2)
sys.stderr = file
# Restores stdout to default - and stderr
def restore_stdout():
sys.stdout.flush()
sys.stdout.close()
os.dup2(oldstdout, 1)
os.dup2(oldstderr, 2)
sys.stdout = oldsysstdout
sys.stderr = oldsysstderr
Чтобы использовать его:
Отмените все выходные данные stdout и stderr с помощью:
cancel_stdout(stderr=Истина)
Направьте все stdout (но не stderr) в файл:
reroute_stdout('output.txt')
Чтобы восстановить stdout и stderr:
restore_stdout()
Ваш класс будет работать очень хорошо (за исключением write()
имя метода - его нужно вызвать write()
в нижнем регистре). Просто убедитесь, что вы сохранили копию sys.stdout
в другой переменной.
Если вы используете *NIX, вы можете сделать sys.stdout = open('/dev/null')
, но это менее переносимо, чем прокатка собственного класса.
Я использую это. Перенаправление на строку, которую вы впоследствии игнорируете. Я использую контекстный менеджер, чтобы сохранить и восстановить исходную настройку дляstdout
.
from io import StringIO
...
with StringIO() as out:
with stdout_redirected(out):
# Do your thing
гдеstdout_redirected
определяется как:
from contextlib import contextmanager
@contextmanager
def stdout_redirected(new_stdout):
save_stdout = sys.stdout
sys.stdout = new_stdout
try:
yield None
finally:
sys.stdout = save_stdout
Почему бы тебе не попробовать это?
sys.stdout.close()
sys.stderr.close()
Добавлю здесь несколько примеров к многочисленным ответам:
import argparse
import contextlib
class NonWritable:
def write(self, *args, **kwargs):
pass
parser = argparse.ArgumentParser(description='my program')
parser.add_argument("-p", "--param", help="my parameter", type=str, required=True)
#with contextlib.redirect_stdout(None): # No effect as `argparse` will output to `stderr`
#with contextlib.redirect_stderr(None): # AttributeError: 'NoneType' object has no attribute 'write'
with contextlib.redirect_stderr(NonWritable): # this works!
args = parser.parse_args()
Нормальный вывод будет:
>python TEST.py
usage: TEST.py [-h] -p PARAM
TEST.py: error: the following arguments are required: -p/--param