Перенаправление stdout в "ничего" в python

У меня есть большой проект, состоящий из достаточно большого количества модулей, каждый из которых печатает что-то на стандартный вывод. Теперь, когда проект вырос в размерах, больших нет. операторов 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 для этого? Или есть что-то лучше этого?

Ответ 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

Ответ 2

Хороший способ сделать это - создать небольшой обработчик контекста, в который вы вставляете свои отпечатки. Затем вы просто используете, чтобы 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.

Ответ 3

Если вы используете Python 3.4 или выше, есть простое и безопасное решение с использованием стандартной библиотеки:

import contextlib

with contextlib.redirect_stdout(None):
  print("This won't print!")

Ответ 4

(по крайней мере, в моей системе), похоже, что запись в 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

Ответ 5

Если вы находитесь в среде Unix (включая Linux), вы можете перенаправить вывод на /dev/null:

python myprogram.py > /dev/null

И для Windows:

python myprogram.py > nul

Ответ 6

В следующем проекте используйте модуль регистрации, а не печатание дерьма в stdout/stderr.

Ответ 7

Как насчет этого:

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 и более поздних версиях.

Ответ 8

Ваш класс будет работать отлично (за исключением имени метода write() - его нужно называть write(), строчным). Просто убедитесь, что вы сохранили копию sys.stdout в другой переменной.

Если вы используете * NIX, вы можете сделать sys.stdout = open('/dev/null'), но это менее переносимо, чем сканирование собственного класса.

Ответ 9

Вы можете просто посмеяться над этим.

import mock

sys.stdout = mock.MagicMock()

Ответ 10

Почему бы вам не попробовать это?

sys.stdout.close()
sys.stderr.close()

Ответ 11

sys.stdout = None

Это нормально для print(). Но это может вызвать ошибку, если вы вызываете любой метод sys.stdout, например sys.stdout.write().

В документах есть примечание:

При некоторых условиях stdin, stdout и stderr, а также исходные значения stdin, stdout и stderr могут быть None. Обычно это относится к приложениям с графическим интерфейсом Windows, которые подключены к консоли, а приложения Python начинаются с pythonw.