Перенаправление 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
Другие вопросы по тегам