78 votes

Python: Temporairement Rediriger stdout/stderr

Est-il possible de rediriger temporairement stdout/stderr en Python (c'est à dire pour la durée d'une méthode)?

Edit:

Le problème avec les solutions actuelles (que j'ai au premier souvenir, mais ensuite il a oublié), c'est qu'ils ne sont pas de redirection; plutôt, ils ont juste remplacer les cours d'eau dans leur intégralité. Par conséquent, si une méthode a un local copie de la variable pour une raison quelconque (par exemple, parce que le courant était passé comme un paramètre à quelque chose), ça ne marchera pas.

Toutes les solutions?

99voto

Rob Cowie Points 10471

Vous pouvez aussi mettre la redirection de la logique dans un contextmanager.

import os
import sys

class RedirectStdStreams(object):
    def __init__(self, stdout=None, stderr=None):
        self._stdout = stdout or sys.stdout
        self._stderr = stderr or sys.stderr

    def __enter__(self):
        self.old_stdout, self.old_stderr = sys.stdout, sys.stderr
        self.old_stdout.flush(); self.old_stderr.flush()
        sys.stdout, sys.stderr = self._stdout, self._stderr

    def __exit__(self, exc_type, exc_value, traceback):
        self._stdout.flush(); self._stderr.flush()
        sys.stdout = self.old_stdout
        sys.stderr = self.old_stderr

if __name__ == '__main__':

    devnull = open(os.devnull, 'w')
    print('Fubar')

    with RedirectStdStreams(stdout=devnull, stderr=devnull):
        print("You'll never see me")

    print("I'm back!")

25voto

J.F. Sebastian Points 102961

Pour résoudre le problème d'une fonction peut avoir mis en cache sys.stdout flux comme une variable locale, et par conséquent, le remplacement de la global sys.stdout ne fonctionne pas à l'intérieur de cette fonction, vous pouvez rediriger dans un fichier descripteur de niveau (sys.stdout.fileno()) par ex.:

from __future__ import print_function
import os
import sys

def some_function_with_cached_sys_stdout(stdout=sys.stdout):
    print('cached stdout', file=stdout)

with stdout_redirected(to=os.devnull), merged_stderr_stdout():
    print('stdout goes to devnull')
    some_function_with_cached_sys_stdout()
    print('stderr also goes to stdout that goes to devnull', file=sys.stderr)
print('stdout is back')
some_function_with_cached_sys_stdout()
print('stderr is back', file=sys.stderr)

stdout_redirected() redirige toutes les sorties pour sys.stdout.fileno() d'un nom de fichier, le fichier d'objet, ou descripteur de fichier (os.devnull dans l'exemple).

stdout_redirected() et merged_stderr_stdout() sont définies ici.

21voto

Senthil Kumaran Points 14934

Je ne suis pas sûr de ce que la redirection temporaire de moyens. Mais, vous pouvez réattribuer des cours d'eau, ce et de le remettre en arrière.

temp = sys.stdout
sys.stdout = sys.stderr
sys.stderr = temp

Aussi à écrire à sys.stderr dans un délai d'impression stmts comme ça.

 print >> sys.stderr, "Error in atexit._run_exitfuncs:"

L'imprimé ordinaire va vers stdout.

15voto

larsmans Points 167484

C'est possible avec un décorateur telles que les suivantes:

import sys

def redirect_stderr_stdout(stderr=sys.stderr, stdout=sys.stdout):
    def wrap(f):
        def newf(*args, **kwargs):
            old_stderr, old_stdout = sys.stderr, sys.stdout
            sys.stderr = stderr
            sys.stdout = stdout
            try:
                return f(*args, **kwargs)
            finally:
                sys.stderr, sys.stdout = old_stderr, old_stdout

        return newf
    return wrap

Utiliser comme:

@redirect_stderr_stdout(some_logging_stream, the_console):
def fun(...):
    # whatever

ou, si vous ne voulez pas modifier la source pour fun, appeler directement

redirect_stderr_stdout(some_logging_stream, the_console)(fun)

Mais notez que ce n'est pas thread-safe.

4voto

Marc Abramowitz Points 1089

Voici un gestionnaire de contexte que j'ai trouvé utile. Belles choses sur ce que vous pouvez l'utiliser avec l' with déclaration et il gère également la redirection pour les processus enfants.

import contextlib


@contextlib.contextmanager
def stdchannel_redirected(stdchannel, dest_filename):
    """
    A context manager to temporarily redirect stdout or stderr

    e.g.:

    with stdchannel_redirected(sys.stderr, os.devnull):
        ...
    """

    try:
        oldstdchannel = os.dup(stdchannel.fileno())
        dest_file = open(dest_filename, 'w')
        os.dup2(dest_file.fileno(), stdchannel.fileno())

        yield
    finally:
        if oldstdchannel is not None:
            os.dup2(oldstdchannel, stdchannel.fileno())
        if dest_file is not None:
            dest_file.close()

Le contexte pour laquelle j'ai créé c'est à ce blog.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X