2009-07-04 10 views
13

Sto provando a sottoclasse la classe integrata file in Python per aggiungere alcune funzionalità extra a stdin e stdout. Ecco il codice che ho finora:Come si sottoclasse il tipo di file in 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') 

Lo scopo è quello di aggiungere un timestamp all'inizio di ogni messaggio, e per registrare tutto ciò che un file di log. Tuttavia, il problema che ho incontrato è che se faccio questo:

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

Poi, quando provo a fare print 'foo', ho un ValueError: I/O operation on closed file. Non posso chiamare significativamente file.__init__() nel mio __init__(), poiché non desidero aprire un nuovo file e non posso assegnare neanche self.closed = False, poiché si tratta di un attributo di sola lettura.

Come posso modificare questo in modo che possa fare print 'foo' e in modo che supporti tutti gli attributi e i metodi standard file?

risposta

12

Calling file.__init__ è abbastanza fattibile (ad esempio, su '/ dev/null'), ma nessuna vera utilizzo perché il tentativo di forzatura dei write non "prendere" ai fini della print dichiarazioni - quest'ultimo chiama internamente il vero file.write quando vede che sys.stdout è un'istanza reale di file (e ereditando l'hai fatto così).

print non ha veramente bisogno qualsiasi altro metodo, tranne write, in modo da rendere la vostra eredita dalla classe object invece di file funzionerà.

Se sono necessari altri metodi di file (ad esempio, print non è tutto quello che stai facendo), ti consigliamo di implementarli tu stesso.

+0

Non sono sicuro di quale funzione avrò bisogno, ma mi piacerebbe sicuramente che alcuni di quelli più comunemente usati siano implementati. Credo che mi limiterò a mordere il proiettile e ad attuare quelli che mi servono, e derivare dall'oggetto invece che dal file. –

+0

Quali metodi oltre alla scrittura sono comunemente usati su sys.stdout? Forse writelines, close, flush - tutto abbastanza facile (e dovresti implementarle tu stesso comunque - come potrebbe il tipo di file sapere chiudere o svuotare entrambi i tuoi file comunque?! -) –

+0

Sì, hai ragione , osservando l'interfaccia del file, tutto ciò di cui ho veramente bisogno sono scrivere, scrivere, chiudere e svuotare. Qualunque altra cosa non dovrebbe mai essere chiamata su sys.stdout o sys.stderr. –

2

Si può così evitare di utilizzare super:

class SuperFile(file): 

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

sarete in grado di scrivere con esso.

+0

scusate, ho avuto un bug, questo funziona bene. –

Problemi correlati