2009-07-04 2 views
13

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

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', я получаю ValueError: I/O operation on closed file. Я не могу с полным основанием называть file.__init__() в моем __init__(), так как я не хочу открывать новый файл, и я не могу назначить self.closed = False, так как это атрибут только для чтения.

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

ответ

12

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

print действительно не нужен никакой другой метод, кроме write, так что делает ваш класс наследует от object вместо file будет работать.

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

+0

Я не уверен, какая именно функция мне понадобится, но я бы хотел, чтобы некоторые из наиболее часто используемых были реализованы. Думаю, я просто укушу пулю и реализую те, которые мне нужны, и получаю от объекта вместо файла. –

+0

Какие методы помимо записи обычно используются в sys.stdout? Возможно, сценарии, тесные, флеш - все довольно легко (и вам все равно придется их реализовать самостоятельно - как может тип файла знать, чтобы закрыть или сбросить оба ваших файла в любом случае?) –

+0

Да, вы правы , просматривая интерфейс файла, мне действительно нужно писать, писать, закрывать и скрывать. Ничего другого на самом деле не следует называть sys.stdout или sys.stderr. –

2

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

class SuperFile(file): 

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

Вы будете в состоянии написать с ним.

+0

Извините, у меня была ошибка, это работает отлично. –