Safely dealing with arbitrary file objects

Scott David Daniels Scott.Daniels at Acm.Org
Sun Oct 14 01:20:38 EDT 2007


Steven D'Aprano wrote:
> I have found myself writing functions rather like these:
> 
> def openfile(filename):
>     if filename == '-':
>         # convention for shell scripts in Unix-land is to use
>         # '-' for stdin/stdout for reading/writing.
>         outfile = sys.stdout
>     if filename == '2-':
>         outfile = sys.stderr
>     else:
>         outfile = file(filename, 'w')
>     return outfile
> 
> def closefile(fileobj):
>     # don't close standard file objects, or their replacements
>     if not fileobj in (sys.stdout, sys.stderr, sys.stdin, 
>     sys.__stdout__, sys.__stderr__, sys.__stdin__):
>         fileobj.close()
> 
> 
> def processfile(filename):
>     outfile = openfile(filename)
>     try:
>         # lots of processing here, which may raise exceptions
>         var = "stuff happens"
>         outfile.write(var)
>     finally:
>         closefile(outfile)
> 
> 
> 
> A question:
> 
> I know I'm being paranoid about not closing files I shouldn't close, but 
> am I being excessively paranoid, or not paranoid enough?
> 
> Suggestions for improvements welcome; while I'm happy to read suggestions 
> using the new with statement, I can't yet rely on having Python 2.5 or 
> better so I have to stick to try...finally.

How about a wrapper that passes along all but 'close', so you don't
have to worry about closing something you means to leave open.
Something like:

     class DontCloseOutput(file):
         '''subclass file only to allow isinstance checks to work out'''
         def __init__(self, referent):
             self._actual = referent
             self.closed = False

         def close(self):
             self.closed = True

         def write(self, data):
             if self.closed:
                 raise IOError('Tried to write closed pseudo-file')
             return self._actual.write(data)


     def writeopen(filename):
         if filename == '-':
             # convention for shell scripts in Unix-land is to use
             # '-' for stdin/stdout for reading/writing.
             return DontCloseOutput(sys.stdout)
         if filename == '2-':
             return DontCloseOutput(sys.stderr)
         else:
             return open(filename, 'w')  # BTW, open is the preferred way
                                         # file was for a short time.

You of course can do similar things (probably forwarding more message)
with readopen.

-Scott David Daniels
Scott.Daniels at Acm.Org



More information about the Python-list mailing list