Reading Until EOF

Ian Bicking ianb at colorstudy.com
Tue Oct 21 14:51:13 EDT 2003


On Tuesday, October 21, 2003, at 01:27 PM, Scott Brady Drummonds wrote:
> Hi, everyone,
>
> I'm a Python novice and would love some tips on how I should perform 
> the
> following task: I'd like to have my Python script read objects (using 
> their
> constructors) and terminate gracefully when an EOF is encountered.  My 
> first
> attempt looked like this:
>
>   #  This is enclosed in a 'try' block
>   file = open(...)
>   while 1:
>     #  The Object constructor raises an exception for end-of-file
>     object = Object(file)
>     self.list = self.list + [object]

Maybe you don't want to use a constructor, maybe you want to use a 
function.  The function could return None when there were no more 
objects to be found.

But that might not be possible, because maybe you won't know if the 
file is truncated until you are part way through constructing the 
object.  In this case an exception probably the best way to go, i.e.:

while 1:
     try:
         self.list.append(Object(file))
     except EOFError:
         break

> However, I'm not entirely comfortable having the Object constructor 
> raise an
> exception when the end-of-file is hit.  Per my experience with C++, 
> this
> does not qualify as "exceptional behavior".  Frankly, it is accepted.  
> I'd
> like to save the exceptions for true exceptions.  My next guess:

No need to save exceptions -- they aren't a scarce resource.  If you 
are worried about ambiguity (which probably isn't problem in this case) 
you can define your own exception, like:

class ObjectEOFError(EOFError): pass

class Object:
     def __init__(self, file):
         try:
             tok = getToken(file)
         except EOFError: # We expect this might happen...
             raise ObjectEOFError

This can be more useful when you might get a ValueError or TypeError, 
which could get generated anywhere (even though you might only want to 
catch an exception created in one place).

>   #  This is enclosed in a 'try' block
>   file = open(...)
>   while object = Object(file):
>     self.list = self.list + [object]
>
> With this implementation, the file reading stops both with an exception
> (raised by a parsing error, as an example) and when the Object 
> constructor
> returns something that makes the while conditional fail.  However, 
> therein
> lies the rub: I don't know how to do this in Python.
>
> Is there a way for me to make the second implementation work?  Is 
> there an
> "empty" operator in Python that I could overload?  Can I have a 
> constructor
> return 'null'?

It's kind of a pain, but you can do that.  You can use the __new__ 
method.  Or you can use a class method, like:

class Object(object): # Remember the (object)!
     def fromFile(cls, file):
         try:
             return cls(file)
         except EOFError:
             return None
     fromFile = classmethod(fromFile)

Then use Object.fromFile(file), which returns None when there's an 
exception.  Or you can use a function which does the same (though you 
seem to be construction just such a function).  I always forget the 
magical __new__ incantation, maybe it's something like:

class Object(object):
     def __new__(cls, file):
         try:
             inst = object.__new__(cls, file)
         except EOFError:
             return None

I'm not entirely clear if that will work though -- it depends if 
__init__ is called after __new__, or during object.__new__.  I don't 
like the __new__ method -- it's always a little magical to me -- and I 
wouldn't really recommend it.

--
Ian Bicking | ianb at colorstudy.com | http://blog.ianbicking.org






More information about the Python-list mailing list