Subclassing file and getting around the file.__init__ rigidity

Peter Otten __peter__ at web.de
Sat Apr 3 12:50:19 EST 2004


Jan Burgy wrote:

> Hi all y'all,
> 
> Consider the class down below. I've implemented it just because I
> needed the pushback method. Now of course the third line in __init__
> doesn't work and I even understand why. My question is: is there any
> way to make it work? Somebody proposed a patch for fileobject.c to
> allow stuff like fp = file(fp1.fileno()) but it looks like it's been
> rejected. I won't so bold as to request a change in Python. Should I
> try to re-write this class in C? Although I know C I'm much to lazy to
> take on the entire python API, not that it doesn't look nice.
> 
> Thanks for your help
> 
> Jan Burgy
> 
> class BufferedFile(file):
> 
>     def __init__(self, name):
>         if type(name) == file:
>             self = name                   # DOESN'T WORK!
>         else:
>             file.__init__(self, name)
>         self.buffer = None
>         
>     def readline(self):
>         if self.buffer:
>             i = self.buffer.find("\n")
>             line, self.buffer = self.buffer[:i], self.buffer[:i+1]
>         else:
>             line = file.readline(self)
>         return line
> 
>     def pushback(self, line):
>         self.buffer = line + self.buffer

Here's a way to force it by using a wrapper instead of a subclass:

class BufferedFile(object):
    def __init__(self, name, *more):
        if isinstance(name, basestring):
            self.fo = file(name, *more)
        else:
            self.fo = name
            assert len(more) == 0
        self.buffer = []

    def readline(self):
        if self.buffer:
            return self.buffer.pop()
        return self.fo.readline()

    def __iter__(self):
        return self

    def next(self):
        result = self.readline()
        if not result:
            raise StopIteration
        return result

    def pushback(self, line):
        self.buffer.append(line)

    def __getattr__(self, name):
        return getattr(self.fo, name)

Unfortunately it grew clumsier than I originaly expected because of the
duplicated interface (next() and readline() for essentially the same
thing). Personally, I would recommend using the subclass approach and drop
the requirement of accepting a file object as an __init__() parameter.
Still the above has the advantage of working with "real files" and StringIO
objects alike (not tested, so don't blame me).


Peter




More information about the Python-list mailing list