2009-07-04 3 views
13

J'essaie de sous-classer la classe file intégrée en Python pour ajouter quelques fonctionnalités supplémentaires à stdin et stdout. Voici le code que j'ai jusqu'à présent:Comment sous-classez-vous le type de fichier en 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') 

Le but est d'ajouter un horodatage au début de chaque message, et de se connecter à tout un fichier journal. Cependant, le problème que je tombe sur est que si je fais ceci:

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

Puis, quand je tente de faire print 'foo', je reçois un ValueError: I/O operation on closed file. Je ne peux pas appeler de façon significative file.__init__() dans mon __init__(), puisque je ne veux pas ouvrir un nouveau fichier, et je ne peux pas attribuer self.closed = False non plus, puisqu'il s'agit d'un attribut en lecture seule.

Comment puis-je modifier ceci afin que je puisse faire print 'foo', et qu'il prenne en charge tous les attributs et méthodes standard file?

Répondre

12

Appel file.__init__ est tout à fait possible (par exemple, sur «/dev/null ») mais sans réelle parce que votre tentative de substitution de write ne pas « prendre » aux fins de print déclarations - ce dernier appelle en interne le réel file.write quand il voit que sys.stdout est une instance réelle de file (et en héritant vous avez fait ainsi).

print n'a pas vraiment besoin d'une autre méthode, sauf write, rendant ainsi votre Hériter de classe de object au lieu de file fonctionnera.

Si vous avez besoin d'autres méthodes de fichiers (par exemple, print n'est pas tout ce que vous faites), il est préférable de les implémenter vous-même.

+0

Je ne sais pas exactement quelle fonction j'aurai besoin, mais j'aimerais bien que certaines des plus utilisées soient implémentées. Je suppose que je vais juste mordre la balle et mettre en œuvre ceux dont j'ai besoin, et dériver de l'objet au lieu du fichier. –

+0

Quelles sont les méthodes autres que l'écriture sont couramment utilisés sur sys.stdout? Peut-être que les writelines, close, flush - tout est assez facile (et vous devrez les implémenter vous-même de toute façon - comment le type de fichier pourrait-il fermer ou vider vos deux fichiers?) -) –

+0

Ouais, vous avez raison , en regardant par-dessus l'interface de fichier, tout ce dont j'ai vraiment besoin est d'écrire, d'écrire, de fermer, et de faire flush. Tout le reste ne devrait jamais être appelé sur sys.stdout ou sys.stderr. –

2

Vous pouvez ainsi éviter d'utiliser super:

class SuperFile(file): 

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

Vous serez en mesure d'écrire avec elle.

+0

désolé, j'ai eu un bug, cela fonctionne très bien. –

Questions connexes