12

I'm pretty new to Python so I am still just learning the language. One of the things I came across was reassigning sys.stdout to change the default output of print. So I wrote this as a test:

import sys
sys.stdout = open('log.txt','a')
print('hey')
sys.stdout.close()
sys.stdout = sys.__stdout__
print('hi')

'Hey' is written to the file, but 'hi' shows up nowhere. However, this works as expected, and 'hey' is written to the file, and 'hi' is printed to the console output:

import sys
sys.__stdout__ = sys.stdout
sys.stdout = open(r'C:\Users\Vincent\Documents\Python\log.txt','a')
print('hey')
sys.stdout.close()
sys.stdout = sys.__stdout__
print('hi')

In short its a small problem that doesnt really matter too much, I am just wondering if there's a discernible reason why its not working the way it should. I have tried this on Windows 7 Home Premium with IDLE and pyscripter on v3.2.3 and my portable python v3.2.1.

Vince
  • 121
  • 1
  • 4
  • How do you run this script? You didn't tell if the first `print` worked or not. *When I assign some other variable to sys.stdout in the beginning and change it back it works* It would be better to write code illustrating this and describe it's output. – Piotr Dobrogost Oct 04 '12 at 10:24

3 Answers3

7

In IDLE, sys.__stdout__ is the program's original standard output - which goes nowhere, since it's not a console application. In other words, IDLE itself has already replaced sys.stdout with something else (its own console window), so you're taking two steps backwards by replacing your own stdout with __stdout__.

jasonharper
  • 9,450
  • 2
  • 18
  • 42
2

I would try this workaround (not using sys.__stdout__ at all because your environment could have made both sys.stdout and sys.__stdout__ distinct):

old_stdout = sys.stdout
sys.stdout = open('log.txt','a')
print('hey')
sys.stdout.close()
sys.stdout = old_stdout

backuping the reference of sys.stdout seems the safest way to do it. Worked in another slightly different case: stdout redirect from Jupyter notebook is landing in the terminal

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
0

Here is a context manager that backups the old states of sys.std<in|out|err> for you, as a complement to the other answers.

Personally, I use it with my programs based on PyQt5 where the standard output is redirected towards a text-based widget as long as the app is running. The output is redirected back to my IDE's console once the app is closed.

import sys

class SysStdRedirection:
    """Any change done to `sys.std<in|out|err>` inside this context manager will
       be reverted upon exit."""

    def __init__(self):
        for x in ("stdin", "stdout", "stderr"):
            setattr(self, x, getattr(sys, x))

    def __enter__(self):
        pass

    def __exit__(self, error_type=None, value=None, traceback=None):
        for x in ("stdin", "stdout", "stderr"):
            setattr(sys, x, getattr(self, x))

Usage:

with SysStdRedirection():
    sys.stdout = open('log.txt', 'a')
    print('hey')
    sys.stdout.close()
print('hi')
Guimoute
  • 4,407
  • 3
  • 12
  • 28