Подавление вывода модуля, вызывающего вне библиотеки

У меня неприятная проблема при использовании библиотеки машинного обучения PyML. PyML использует libsvm для обучения классификатора SVM. Проблема в том, что libsvm выводит некоторый текст на стандартный вывод. Но поскольку это не в Python, я не могу его перехватить. Я пробовал использовать методы, описанные в проблеме Отключить стандартный вывод функции в Python, не уничтожая sys.stdout и не восстанавливая каждый вызов функции, но ничего из этого не помогает.

Есть ли способ как это сделать. Изменение PyML не вариант.


person Rok    schedule 14.11.2010    source источник
comment
Вы проверяете, может быть, он пишет в sys.stderr, а не в sys.stdout !!!   -  person mouad    schedule 14.11.2010
comment
связанные: Перенаправить stdout в файл на Python? - в данном случае это os.devnull.   -  person jfs    schedule 07.05.2014


Ответы (4)


Откройте /dev/null для записи, используйте os.dup() для копирования stdout и используйте os.dup2() для копирования вашего открытого /dev/null в stdout. Используйте os.dup2(), чтобы скопировать скопированный стандартный вывод обратно в реальный стандартный вывод после.

devnull = open('/dev/null', 'w')
oldstdout_fno = os.dup(sys.stdout.fileno())
os.dup2(devnull.fileno(), 1)
makesomenoise()
os.dup2(oldstdout_fno, 1)
person Ignacio Vazquez-Abrams    schedule 14.11.2010
comment
'oldstdout = os.dup (sys.stdout)' выдает ошибку типа 'требуется целое число' - person Rok; 14.11.2010
comment
разобрался, требуются sys.stdout.fileno () и devnull.fileno (), и после этого он работает, спасибо !! - person Rok; 14.11.2010
comment
Разве вы не должны закрыть devnull в конце с помощью devnull.close() или открыть его с помощью оператора with? - person MrUser; 09.03.2016
comment
Рид, твой ответ мне все еще не подходит. Мне нужен os.fsync(devnull.fileno()) перед финальным dup2. Для отладки попробуйте import pybullet as pb как то, что вы хотите заглушить :) - person andrea; 30.10.2020

Дэйв Смит прекрасно ответил на этот вопрос в своем блог. По сути, он красиво завершает ответ Игнасио:

def suppress_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:  
            yield
        finally:
            sys.stdout = old_stdout

Теперь вы можете окружить любую функцию, которая искажает нежелательный шум, в стандартный вывод следующим образом:

print "You can see this"
with suppress_stdout():
    print "You cannot see this"
print "And you can see this again"

Для Python 3 вы можете использовать:

from contextlib import contextmanager
import os
import sys

@contextmanager
def suppress_stdout():
    with open(os.devnull, "w") as devnull:
        old_stdout = sys.stdout
        sys.stdout = devnull
        try:  
            yield
        finally:
            sys.stdout = old_stdout
person Manu CJ    schedule 11.01.2018
comment
Эти решения могут только подавлять вывод, произведенный в python. - person Vic; 23.05.2019
comment
Наверное, да. Кроме того, я обнаружил, что это решение не может подавить некоторые выходные данные python, например, индикатор выполнения TQDM удается распечатать в Stdout, даже когда в этом контексте, не знаю почему. Тем не менее, я обнаружил, что в большинстве случаев в Python это работает. - person Manu CJ; 23.05.2019
comment
Индикатор выполнения TQDM по умолчанию выводится в stderr, чтобы подавить его, вам также потребуется перенаправить sys.stderr - person Majo; 11.12.2020

У меня была такая же проблема, и я исправил ее вот так:

from cStringIO import StringIO

def wrapped_svm_predict(*args):
    """Run :func:`svm_predict` with no *stdout* output."""
    so, sys.stdout = sys.stdout, StringIO()
    ret = svm_predict(*args)
    sys.stdout = so
    return ret
person Oben Sonne    schedule 23.02.2011
comment
Это будет работать, если svm_predict - это вывод, полученный из python, но не из общей библиотеки, которую вызывает python, что, как я считаю, является тем, о чем спрашивал OP. - person Alex Flint; 17.10.2012
comment
Для меня это работало с использованием привязок Python к libsvm. Думаю, для PyML ситуация аналогичная. Stdout - это свойство процесса, т.е. моя упаковка (а также решение Ignacio) отлично работает до тех пор, пока внешние функции не используются через подпроцессы. Он потерпит неудачу только в том случае, если кто-то откроет /dev/stdout для записи вывода. - person Oben Sonne; 18.10.2012
comment
Это именно то, что делает большинство разделяемых библиотек, поэтому это решение не будет работать для большинства людей. Вышеупомянутое решение будет ближе к тому, что нужно запрашивающему. - person kamelkev; 01.07.2013

У меня была аналогичная проблема с инициализацией portaudio / PyAudio. Я начал с ответа Рейда, который сработал. Хотя вместо этого мне нужно было перенаправить stderr. Итак, вот обновленная кроссплатформенная версия, которая перенаправляет оба:

import sys, os

# hide diagnostic output
with open(os.devnull, 'w') as devnull:
    # suppress stdout
    orig_stdout_fno = os.dup(sys.stdout.fileno())
    os.dup2(devnull.fileno(), 1)
    # suppress stderr
    orig_stderr_fno = os.dup(sys.stderr.fileno())
    os.dup2(devnull.fileno(), 2)

    print('*** stdout should be hidden!  ****')
    print('*** stderr should be too!  ****',
          file=sys.stderr)

    os.dup2(orig_stdout_fno, 1)  # restore stdout
    os.dup2(orig_stderr_fno, 2)  # restore stderr

print('done.')

Должно быть легко закомментировать ненужную часть.

person Gringo Suave    schedule 05.03.2020