Python subclassing file types
Tuesday, 3 June 2008
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?
No. 1 — June 11th, 2008 at 6:18 am
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.