Reading Until EOF

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Scott Brady Drummonds

    Reading Until EOF

    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]

    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 "exceptiona l behavior". Frankly, it is accepted. I'd
    like to save the exceptions for true exceptions. My next guess:

    # 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'?

    Thanks!
    Scott

    --
    Remove ".nospam" from the user ID in my e-mail to reply via e-mail.


  • Kirk Strauser

    #2
    Re: Reading Until EOF

    -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    At 2003-10-21T18:27:57Z, "Scott Brady Drummonds" <scott.b.drummo nds.nospam@inte l.com> writes:
    [color=blue]
    > Per my experience with C++, this does not qualify as "exceptiona l
    > behavior". Frankly, it is accepted. I'd like to save the exceptions for
    > true exceptions. My next guess:[/color]

    But it *is* exceptional behavior for the file read to fail. The normal
    behavior is for the call to succeed, right?

    Exceptions are handy for all sorts of things. One of my projects uses
    something like:

    class Success(Excepti on):
    def __init__(self, added = 0, deleted = 0, modified = 0):
    self.added = added
    self.deleted = deleted
    self.modified = modified

    to hold return values from various calls. I use it like:

    try:
    SomeDatabaseQue ry()
    except Success, result:
    print 'Just added %d new entries.' % result.added
    except:
    print 'The query failed.'

    Don't limit yourself to a particular style simply because of the name.
    - --
    Kirk Strauser
    The Strauser Group
    Open. Solutions. Simple.

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.2.3 (GNU/Linux)

    iD8DBQE/lYgS5sRg+Y0CpvE RAm9uAKCQsxlz2U 7OgR/WI3FLSJKmACO0mw CePe9H
    d9mWtYpgEYOoDe7 XvYjBm4E=
    =2ZUb
    -----END PGP SIGNATURE-----

    Comment

    • Michael Geary

      #3
      Re: Reading Until EOF

      > > Per my experience with C++, [end of file] does not qualify[color=blue][color=green]
      > > as "exceptiona l behavior". Frankly, it is [expected]. I'd
      > > like to save the exceptions for true exceptions.[/color][/color]
      [color=blue]
      > But it *is* exceptional behavior for the file read to fail. The
      > normal behavior is for the call to succeed, right?[/color]

      In C++, it would be considered bad style to use an exception to handle EOF.
      The idea is that reaching EOF is something that you *expect* to happen, even
      if only once. Similarly, the StopIteration exception would seem very odd to
      a C++ programmer, since you expect to reach the end of an iteration
      eventually.

      You might use a C++ exception to handle something like a disk read
      error--something that you do not expect to happen in the normal course of
      events.

      I realize the philosophy in Python is different--just trying to help clarify
      why the OP is troubled by Python's more liberal use of exceptions. Anyone
      coming from a C++ background is likely to have the same reaction at first.

      -Mike


      Comment

      • Alex Martelli

        #4
        Re: Reading Until EOF

        Scott Brady Drummonds wrote:
        ...[color=blue]
        > # 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[/color]

        It's a bad idea, as others have pointed out, but, sure -- as long as you
        change this into something like:
        while True:
        object = Object(file)
        if object is None: break
        self.list.appen d(object)
        or -- perhaps a bit more Pythonically, but otherwise equivalently:
        def Objfromfile(): return Object(file)
        self.list.exten d([ object for object in iter(Objfromfil e, None) ])
        [color=blue]
        > "empty" operator in Python that I could overload? Can I have a
        > constructor return 'null'?[/color]

        I'm not sure what an "empty operator" would be. You can easily
        make a function return None; use a factory function instead of the
        bare ctor and you're all set (you'd do it that way in C++ too, and
        there you'd have no alternative to that OR an exception).

        You _CAN_ have Object.__new__ return what you want -- iff it
        returns an instance of Object, that is then passed to Object.__init__ .

        Basically calling Object(xxx) is like calling a function that does:
        def equivalent(xxx) :
        result = Object.__new__( Object, xxx)
        if isinstance(resu lt, Object): Object.__init__ (result, xxx)
        return result
        but basically, for that to be used the way you want you need to do
        almost all the work in Object.__new__ rather than in __init__ --
        you can afford to let the latter be called only when you're fully
        satisfied you'll be able to construct an Object instance just fine.

        It IS a bad idea, but, if you insist, assuming that Object just
        needs a field of exactly 4 bytes it reads from the file, period;
        where you now have
        def __init__(self, file):
        self.field = file.read(4)
        if len(self.field) != 4: raise EOFError
        have no __init__ at all and instead a __new__:
        def __new__(cls, file):
        result = object.__new__( cls)
        result.field = file.read(4)
        if len(self.field) != 4: return None
        return result

        Using such exoteric techniques to avoid normal idiomatic usage
        and surprise every Python-aware reader of your code IS a bad
        idea. Be prepared to defend it craftily at the first code review!-)


        Alex

        Comment

        • Rainer Deyke

          #5
          Re: Reading Until EOF

          Scott Brady Drummonds wrote:[color=blue]
          > 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 "exceptiona l behavior". Frankly,
          > it is accepted. I'd like to save the exceptions for true exceptions.[/color]

          That's a common, but to my mind very strange preference. If you handle an
          exception, the exception is by definition expected and "normal". Exceptions
          are just a way to exit from nested loops and function calls; there is
          nothing "exceptiona l" about them.


          --
          Rainer Deyke - rainerd@eldwood .com - http://eldwood.com


          Comment

          • Peter Otten

            #6
            Re: Reading Until EOF

            Scott Brady Drummonds wrote:
            [color=blue]
            > 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]
            >
            > 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 "exceptiona l behavior". Frankly, it is accepted. I'd
            > like to save the exceptions for true exceptions. My next guess:
            >
            > # 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'?[/color]

            In Python constructors are precious, as there can only be one. I think it's
            the wrong decision to let it construct an object from a file instance. I
            would suggest a factory method instead:

            class Object:
            def __init__(self, word):
            self.word = word
            def __str__(self):
            return self.word

            def factory(instrea m):
            """ construct an Object from the first word of each nonwhite line
            """
            for line in instream:
            if line.strip():
            yield Object(line.spl it()[0].upper())

            instream = file("fromfile. py")
            try:
            alist = [o for o in factory(instrea m)]
            finally:
            instream.close( )

            print "\n".join(map(s tr, alist))

            The factory method could still explicitly raise an Exception for a more
            complex file parsing algorithm (or simply return, if you stick with the
            generator as shown above, but that is a StopIteration exception in
            disguise), where you might want to separate the loop and the object
            generation, but your client code is cleaner anyway.


            Peter


            Comment

            • Ben Finney

              #7
              Re: Reading Until EOF

              On Tue, 21 Oct 2003 20:10:08 GMT, Kirk Strauser wrote:[color=blue]
              > But it *is* exceptional behavior for the file read to fail. The
              > normal behavior is for the call to succeed, right?[/color]

              No, it is a normal result for the call to succeed, and it is a normal
              result for end of file to be reached. The existence of one normal
              result does not make all others exceptional.

              --
              \ "I think it would be a good idea." -- Mahatma Gandhi (when |
              `\ asked what he thought of Western civilization) |
              _o__) |
              Ben Finney <http://bignose.squidly .org/>

              Comment

              • Donn Cave

                #8
                Re: Reading Until EOF

                Quoth Kirk Strauser <kirk@strauser. com>:
                | At 2003-10-21T18:27:57Z, "Scott Brady Drummonds" <scott.b.drummo nds.nospam@=
                | intel.com> writes:
                |
                |> Per my experience with C++, this does not qualify as "exceptiona l
                |> behavior". Frankly, it is accepted. I'd like to save the exceptions for
                |> true exceptions. My next guess:
                |
                | But it *is* exceptional behavior for the file read to fail. The normal
                | behavior is for the call to succeed, right?

                Indeed, let me be the 7th or so person to chime in here. To be
                precise, I think rather than `normal' and `succeed', I would just
                say that the function has a meaning like `next line from file'.
                Functions with such simple meanings can exist because of exceptions -
                we decide what the function means, and we make it truly mean that by
                raising an exception otherwise.

                | Exceptions are handy for all sorts of things. One of my projects uses
                | something like:
                |
                | class Success(Excepti on):
                | def __init__(self, added = 0, deleted = 0, modified = 0):
                | self.added = added
                | self.deleted = deleted
                | self.modified = modified
                |
                | to hold return values from various calls. I use it like:
                |
                | try:
                | SomeDatabaseQue ry()
                | except Success, result:
                | print 'Just added %d new entries.' % result.added
                | except:
                | print 'The query failed.'

                Hm, it isn't so clear why this is a good idea.

                Donn Cave, donn@drizzle.co m

                Comment

                Working...