Ответ 1
Кроссплатформенность:
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
У меня есть большой проект, состоящий из достаточно большого количества модулей, каждый из которых печатает что-то на стандартный вывод. Теперь, когда проект вырос в размерах, больших нет. операторов print
, печатающих много на std-выходе, что сделало программу значительно медленнее.
Итак, теперь я хочу решить во время выполнения, нужно ли печатать что-либо в stdout. Я не могу вносить изменения в модули, так как их много. (Я знаю, что могу перенаправить stdout в файл, но даже это значительно медленнее.)
Итак, мой вопрос заключается в том, как перенаправить stdout на ничего, т.е. как заставить оператор 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.
В настоящее время единственной идеей, которую я имею, является создание класса, который имеет метод записи (который ничего не делает) и перенаправляет stdout на экземпляр этого класса.
class DontPrint(object):
def write(*args): pass
dp = DontPrint()
sys.stdout = dp
Есть ли встроенный механизм в python для этого? Или есть что-то лучше этого?
Кроссплатформенность:
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
-statement отключить весь вывод.
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
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
В следующем проекте используйте модуль регистрации, а не печатание дерьма в stdout/stderr.
Как насчет этого:
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 и более поздних версиях.
Ваш класс будет работать отлично (за исключением имени метода write()
- его нужно называть write()
, строчным). Просто убедитесь, что вы сохранили копию sys.stdout
в другой переменной.
Если вы используете * NIX, вы можете сделать sys.stdout = open('/dev/null')
, но это менее переносимо, чем сканирование собственного класса.
Вы можете просто посмеяться над этим.
import mock
sys.stdout = mock.MagicMock()
Почему бы вам не попробовать это?
sys.stdout.close()
sys.stderr.close()
sys.stdout = None
Это нормально для print()
. Но это может вызвать ошибку, если вы вызываете любой метод sys.stdout, например sys.stdout.write()
.
В документах есть примечание:
При некоторых условиях stdin, stdout и stderr, а также исходные значения stdin, stdout и stderr могут быть None. Обычно это относится к приложениям с графическим интерфейсом Windows, которые подключены к консоли, а приложения Python начинаются с pythonw.