How do you subclass the file type in Python?

file, python, subclass

Solution

Calling `file.__init__` is quite feasible (e.g., on '/dev/null') but no real use because your attempted override of `write` doesn't "take" for the purposes of `print` statements -- the latter internally calls the real `file.write` when it sees that `sys.stdout` is an actual instance of `file` (and by inheriting you've made it so).

`print` doesn't really need any other method except `write`, so making your class inherit from `object` instead of `file` will work.

If you need other file methods (i.e., `print` is not all you're doing), you're best advised to implement them yourself.

Problem

I'm trying to subclass the built-in `file` class in Python to add some extra features to `stdin` and `stdout`. Here's the code I have so far: ``` class TeeWithTimestamp(file): """ Class used to tee the output of a stream (such as stdout or stderr) into another stream, and to add a timestamp to each message printed. """ def __init__(self, file1, file2): """Initializes the TeeWithTimestamp""" self.file1 = file1 self.file2 = file2 self.at_start_of_line = True def write(self, text): """Writes text to both files, prefixed with a timestamp""" if len(text): # Add timestamp if at the start of a line; also add [STDERR] # for stderr if self.at_start_of_line: now = datetime.datetime.now() prefix = now.strftime('[%H:%M:%S] ') if self.file1 == sys.__stderr__: prefix += '[STDERR] ' text = prefix + text self.file1.write(text) self.file2.write(text) self.at_start_of_line = (text[-1] == '\n') ``` The purpose is to add a timestamp to the beginning of each message, and to log everything to a log file. However, the problem I run into is that if I do this: ``` # log_file has already been opened sys.stdout = TeeWithTimestamp(sys.stdout, log_file) ``` Then when I try to do `print 'foo'`, I get a `ValueError: I/O operation on closed file`. I can't meaningfully call `file.__init__()` in my `__init__()`, since I don't want to open a new file, and I can't assign `self.closed = False` either, since it's a read-only attribute. How can I modify this so that I can do `print 'foo'`, and so that it supports all of the standard `file` attributes and methods?

Original source