10

i can silence and restore sys.stdout this way:

import sys
sys.stdout = None
print('hello')  # does not write to stdout
sys.stdout = sys.__stdout__
print('hello')  # writes to stdout

i know i'd better be using contextlib.redirect_stdout which probably does something similar but my question is: why does the above code work?

i'd have assumed python would call things like sys.stdout.write() so whatever i replace sys.stdout with should have a write method (like e.g. io.StringIO) at least.

hiro protagonist
  • 44,693
  • 14
  • 86
  • 111
  • 2
    The footnote in docs says they can be None in some conditions: Under some conditions `stdin`, `stdout` and `stderr` as well as the original values `__stdin__`, `__stdout__` and `__stderr__` can be None. – Ashwini Chaudhary Apr 10 '18 at 15:38
  • 2
    I think this is [the footnote](https://docs.python.org/3.4/library/sys.html#sys.__stdout__) @AshwiniChaudhary may be referring to. – unutbu Apr 10 '18 at 15:41
  • ok, i missed the footnote. thanks! – hiro protagonist Apr 10 '18 at 15:42

1 Answers1

14

print has an explicit check for None.

    /* sys.stdout may be None when FILE* stdout isn't connected */
    if (file == Py_None)
        Py_RETURN_NONE;
user2357112
  • 260,549
  • 28
  • 431
  • 505
  • i was digging through the source code and had trouble finding that (should have grepped for `builtin_print`)... thanks! – hiro protagonist Apr 10 '18 at 15:40
  • 2
    Pypy is also following it as is: https://bitbucket.org/pypy/pypy/src/ed869ecba5203208b21f7ec6f0be86fbffa3fcb0/pypy/module/__builtin__/app_io.py?at=default&fileviewer=file-view-default#app_io.py-92 – Ashwini Chaudhary Apr 10 '18 at 15:47
  • 1
    is it a documented behavior we may rely on? – jfs Apr 11 '18 at 10:51
  • 1
    @jfs: The fact that sys.stdout may be None is [documented](https://docs.python.org/3/library/sys.html#sys.__stdin__); as far as I can tell, the behavior of print when it encounters None for sys.stdout is not. – user2357112 Apr 11 '18 at 16:04