A sequence class that lies about it length

Steven D. Majewski (sdm7g@galen.med.virginia.edu)
Wed, 27 Oct 1993 01:39:57 -0400

Well, while I'm sitting here waiting for restore tapes to
finish spinning, I didn't have anything better I could do,
so I wrote a test of a sequence class that lies about it's
length. Not at all debugged or optimized.

The last 5 lines at the end will test it by printing the
nominal (sometimes untrue) length, the current length of
the internal buffer, and (via pipe to unix 'nl' ) the
line numbered lines of 'flines.py'

- Steve Majewski <sdm7g@Virginia.EDU>

#--------------
# Class Flines
#
# This is a demonstration/test of a class that "lazily" coerces
# the lines of a file into a sequence.
# It was written mostly to test the technique of lying about
# the length of the sequence by +1, except at the end.
# It has the feature that it will continue to try to read
# file when it gets to eof, so even if file continues to grow,
# so that:
# for x in flines_obj: print x[:-1]
# will always print whatever is currently available.
# So it's actually good for something.
# ( But that also means that flines_obj[-1] is very context sensitive! )
#
# <sdm7g@Virginia.EDU>
#
import posix
import builtin

def rdopen( fname ): # open file or pipe for reading
if fname[-1] == '|' :
open = posix.popen
fname = fname[:-1]
else: open = builtin.open
return open( fname, 'r' )

class Flines:
def _lie( self ): return self._len + 1
def _get1( self ):
if self._cache[-1]:
self._cache.append( self._file.readline() )
self._len = self._len + 1
else:
self._cache[-1] = self._file.readline()
def __init__( self, fname ):
self._file = rdopen( fname )
self._cache = [ self._file.readline() ]
self._len = 1
def __len__( self ):
if self._cache[-1]:
return self._lie()
else:
self._get1()
if self._cache[-1]: return self._lie()
else: return self._len
def __getitem__( self, j ):
if j < 0 :
self._get1()
elif j >= self._len :
for index in range( self._len, j+1 ): self._get1()
return self._cache[j]
def __del__(self):
self._file.close()
def __getslice__( self, i, j ):
return self._cache[i:j]

F=Flines('nl -ba flines.py|' )
print '# Test me once...'
for x in F : print len(F),F._len, x[:-1]
print '# Test me twice ... '
for x in F : print len(F),F._len, x[:-1]