Python subclassing file types

I was hoping to write a simple tee class by subclassing file, but there must be further type magic getting in the way when print >> is used.

import sys

class tee(file):
   def write(self, text):
     sys.stdout.write(text)
     file.write(self, text)

fd = tee("output.txt", "w")
print >> fd, "Test 1"
fd.write("Test 2\n")
$ python test.py
Test 2

$ cat output.txt
Test 1
Test 2

Using the dis module, we can tell that print >> is compiled into PRINT_ITEM_TO.

>>> def t(): print >> fd, "foo"
...
>>> import dis; dis.dis(t)
  1           0 LOAD_GLOBAL              0 (fd)
              3 DUP_TOP
              4 LOAD_CONST               1 ('foo')
              7 ROT_TWO
              8 PRINT_ITEM_TO
              9 PRINT_NEWLINE_TO
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE

and looking through ceval.c, searching for PRINT_ITEM_TO yields

 case PRINT_ITEM_TO:
    w = stream = POP();
    /* fall through to PRINT_ITEM */

case PRINT_ITEM:
    v = POP();
    if (stream == NULL || stream == Py_None) {
        w = PySys_GetObject("stdout");
        if (w == NULL) {
            PyErr_SetString(PyExc_RuntimeError,
                    "lost sys.stdout");
            err = -1;
        }
    }
    /* PyFile_SoftSpace() can exececute arbitrary code
       if sys.stdout is an instance with a __getattr__.
       If __getattr__ raises an exception, w will
       be freed, so we need to prevent that temporarily. */
    Py_XINCREF(w);
    if (w != NULL && PyFile_SoftSpace(w, 0))
        err = PyFile_WriteString(" ", w);
    if (err == 0)
        err = PyFile_WriteObject(v, w, Py_PRINT_RAW);


Any ideas why?

One Response to “Python subclassing file types”

  1. Scott Johnson writes:

    Did you ever find out why this is working this way? The tee subclass that you created certainly is handy, and it would be nice to see it working under both circumstances.

Leave a Reply