Как вы подклассифицируете тип файла в Python?

Я пытаюсь подклассифицировать встроенный класс file в Python, чтобы добавить дополнительные функции в stdin и stdout. Вот код, который у меня есть до сих пор:

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')

Цель состоит в том, чтобы добавить временную метку к началу каждого сообщения и записать все в файл журнала. Однако проблема, с которой я сталкиваюсь, заключается в том, что если я это сделаю:

# log_file has already been opened
sys.stdout = TeeWithTimestamp(sys.stdout, log_file)

Тогда, когда я пытаюсь сделать print 'foo', я получаю a ValueError: I/O operation on closed file. Я не могу с полным основанием называть file.__init__() в моем __init__(), так как я не хочу открывать новый файл, и я не могу назначить self.closed = False, так как это атрибут только для чтения.

Как я могу изменить это, чтобы я мог сделать print 'foo', и чтобы он поддерживал все стандартные атрибуты и методы file?

Ответы

Ответ 1

Вызов file.__init__ вполне возможен (например, в '/dev/null'), но не используется, потому что ваше попытка переопределения write не "принимает" для целей операторов print - последний внутренне вызывает реальную file.write, когда видит, что sys.stdout является фактическим экземпляром file (и, наследуя, вы сделали это).

print действительно не нужен какой-либо другой метод, кроме write, поэтому использование класса наследуется от object вместо file.

Если вам нужны другие методы файлов (т.е. print - это еще не все, что вы делаете), вам лучше всего их реализовать.

Ответ 2

Вы также можете избежать использования super:

class SuperFile(file):

    def __init__(self, *args, **kwargs):
        file.__init__(self, *args, **kwargs)

Вы сможете написать с ним.