2017-08-04 2 views
1

Après avoir regardé les autres posts de stackoverflow, je n'arrive pas à comprendre ce problème de redirection. Ce que je voudrais faire est de supprimer à la fois stdout et stderr, puis les restaurer après que l'erreur soit détectée. La suppression fonctionne bien, mais ne les restitue qu'à moitié. Si j'essaie de supprimer et de restaurer stderr et stdout, la suppression fonctionne mais pas la restauration. Si j'essaie seulement de supprimer/restaurer stdout cela fonctionne (mais alors je reçois tout le texte stderr que je ne veux pas). Je ne peux pas expliquer pourquoi il y aurait une différence pour que stderr empêche stdout d'être restauré, en espérant que ça soit le cas (ou si je fais quelque chose de bizarre/stupide)

Heres le code que je veulent travailler mais seulement disparaitre out/err et ne restaure pas (« stdout Restauré » jamais prints):Restauration des sys.stdout et sys.stderr redirigés produisant des résultats impairs

sys.stdout = None 
sys.stderr = None 
try: 
    op_args = op_parse.parse_args(selection.split(' ')) 
except SystemExit: 
    sys.stdout = sys.__stdout__ 
    sys.stderr = sys.__stderr__ 
    print("Restored stdout") 


Heres le code qui supprime stdout et restaure (au coût de l'impression du stderr satanés)

sys.stdout = None 
#sys.stderr = None 
try: 
    op_args = op_parse.parse_args(selection.split(' ')) 
except SystemExit: 
    sys.stdout = sys.__stdout__ 
    #sys.stderr = sys.__stderr__ 
    print("Restored stdout") 

EDIT: J'ai figuré un wo rk autour, mais je suis toujours intéressé par la raison pour laquelle le problème ci-dessus se produit. Mon travail consiste à réaffecter stdout/stderr à = open ("/ dev/null", "w") qui produit le comportement que je veux. Encore une fois je voudrais toujours l'entrée sur le problème original

Répondre

0

Comme un commentaire de haut niveau, cette technique est sujette à erreur et signifie généralement quelque chose d'autre qui va mal. Par exemple - restaurer dans le except ci-dessus (au lieu de dans un finally) signifie que vous restaurez stdout et stderr seulement si vous échouez.

Je soupçonne que votre problème observé peut être dû à votre invocation op_parse. Considérons le code ci-dessous

from __future__ import print_function 
import sys 

sys.stdout = None 
sys.stderr = None 
try: 
    print('before', file=sys.stdout) 
    print('before', file=sys.stderr) 
    # sys.stderr.write('hi') 
    assert False 
except AssertionError: 
    sys.stdout = sys.__stdout__ 
    sys.stderr = sys.__stderr__ 
    print("Restored stdout", file=sys.stdout) 

Quand je lance, je vois: Restored stdout.

Si je ne commente pas la ligne sys.stderr.write, je vois: lost sys.stderr. Une approche plus sûre consisterait à utiliser un contexte pour rediriger stdout/err vers /dev/null ou un IOStream pendant votre opération - ou mieux encore, trouver la fonction de validation utilisée en interne et l'appeler directement au lieu de rechercher une sortie système sur une fonction de haut niveau (est op_parse == opt_parse?)

+0

Merci pour l'entrée, je suis d'accord que la restauration doit se produire dans le bloc finally, dans ce programme de test, je donnais volontairement une erreur à chaque fois, donc je n'ai pas dérangé. J'ai découvert le truc "/ dev/null" avant de voir cela, donc je peux confirmer que votre solution fonctionne. (aussi op_parse n'est pas opt_parse c'était juste un mauvais nom de variable pour représenter 'options parse') – sliceOfPi

2

Vous pouvez le faire un peu plus d'élégance en créant un gestionnaire de contexte:

import os 
from contextlib import contextmanager 

@contextmanager 
def nullout(): 
    save_stdout = sys.stdout 
    save_stderr = sys.stderr 
    sys.stdout = open(os.devnull, 'w') 
    sys.stderr = open(os.devnull, 'w') 
    yield 
    sys.stdout = save_stdout 
    sys.stderr = save_stderr 

with nullout(): 
    op_args = op_parse.parse_args(selection.split(' ')) 

une bonne chose au sujet des gestionnaires de contexte est que le code après la yield va s'exécuter peu importe si un exception se produit ou non.

La raison pour laquelle vous ne pouvez pas définir sys.stdout et sys.stderr à None est probablement parce que None n'a pas une méthode write() ou close() et généralement ne se comporte pas comme un flux de sortie.