Python 3: unbuffered and buffer streams

I use the following snippet to silently (redirect output from) C code called in my Python script:

from ctypes import CDLL, c_void_p
import os
import sys

# Code
class silence(object):
    def __init__(self, stdout=os.devnull):
        self.outfile = stdout

    def __enter__(self):
        # Flush
        sys.__stdout__.flush()

        # Save
        self.saved_stream = sys.stdout
        self.fd = sys.stdout.fileno()
        self.saved_fd = os.dup(self.fd)

        # Open the redirect
        self.new_stream = open(self.outfile, 'wb', 0)

        self.new_fd = self.new_stream.fileno()

        # Replace
        os.dup2(self.new_fd, self.fd)

    def __exit__(self, *args):
        # Flush
        self.saved_stream.flush()

        # Restore
        os.dup2(self.saved_fd, self.fd)
        sys.stdout = self.saved_stream

        # Clean up
        self.new_stream.close()
        os.close(self.saved_fd)


# Test case
libc = CDLL('libc.so.6')


# Silence!
with silence():
    libc.printf(b'Hello from C in silence\n')

The idea is to redirect the fd associated with stdout, and replace it with one associated with the open null device. Unfortunately, in Python 3 it does not work like this:

$ python2.7 test.py
$ python3.3 -u test.py
$ python3.3 test.py
Hello from C in silence

In Python 2.7 and 3.3 with unbuffered output, it works. However, I am not sure what the main reason is. Even if buffering stdout, the call sys.saved_stream.flush()should end with a call fflush(stdout)at level C (reset output to zero device).

What part of the Python 3 I / O model do I not understand?

+4
source share
2 answers

100%, - Py3,

    sys.stdout = os.fdopen(self.fd, 'wb', 0)

, self.fd Python 3.4 ( 3.4, ).

+1

, , :

  • self.saved_stream.flush() __exit__ libc.fflush(None).
  • libc.printf silence(), :

    libc = CDLL('/bin/cygwin1.dll')
    libc.printf(b'')
    

, Python print libc.printf with silence():.

0

All Articles