Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #89610 > unrolled thread

Let exception fire or return None

Started byCecil Westerhof <Cecil@decebal.nl>
First post2015-04-30 09:43 +0200
Last post2015-04-30 14:30 +0200
Articles 10 — 5 participants

Back to article view | Back to comp.lang.python


Contents

  Let exception fire or return None Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 09:43 +0200
    Re: Let exception fire or return None Dave Angel <davea@davea.name> - 2015-04-30 04:18 -0400
      Re: Let exception fire or return None Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 11:13 +0200
    Re: Let exception fire or return None Peter Otten <__peter__@web.de> - 2015-04-30 11:30 +0200
      Re: Let exception fire or return None Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 13:26 +0200
        Re: Let exception fire or return None Peter Otten <__peter__@web.de> - 2015-04-30 14:28 +0200
          Re: Let exception fire or return None Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 16:53 +0200
        Re: Let exception fire or return None Cecil Westerhof <Cecil@decebal.nl> - 2015-04-30 14:22 +0200
    Re: Let exception fire or return None Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-04-30 14:05 +0200
    Re: Let exception fire or return None Antoon Pardon <antoon.pardon@rece.vub.ac.be> - 2015-04-30 14:30 +0200

#89610 — Let exception fire or return None

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 09:43 +0200
SubjectLet exception fire or return None
Message-ID<87bni6awol.fsf@Equus.decebal.nl>
I have a function to fetch a message from a file:
    def get_indexed_message(message_filename, index):
        """
        Get index message from a file, where 0 gets the first message
        """

        return open(expanduser(message_filename), 'r').readlines()[index].rstrip()

What is more the Python way: let the exception fire like this code
when index is to big, or catching it and returning None?

I suppose working zero based is OK.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [next] | [standalone]


#89611

FromDave Angel <davea@davea.name>
Date2015-04-30 04:18 -0400
Message-ID<mailman.119.1430381898.3680.python-list@python.org>
In reply to#89610
On 04/30/2015 03:43 AM, Cecil Westerhof wrote:
> I have a function to fetch a message from a file:
>      def get_indexed_message(message_filename, index):
>          """
>          Get index message from a file, where 0 gets the first message
>          """
>
>          return open(expanduser(message_filename), 'r').readlines()[index].rstrip()
>
> What is more the Python way: let the exception fire like this code
> when index is to big, or catching it and returning None?
>
> I suppose working zero based is OK.
>

Fire an exception.

One advantage is that the exception will pinpoint exactly which line of 
the function had a problem.



-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#89616

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 11:13 +0200
Message-ID<87pp6mvv1a.fsf@Equus.decebal.nl>
In reply to#89611
Op Thursday 30 Apr 2015 10:18 CEST schreef Dave Angel:

> On 04/30/2015 03:43 AM, Cecil Westerhof wrote:
>> I have a function to fetch a message from a file:
>> def get_indexed_message(message_filename, index):
>> """
>> Get index message from a file, where 0 gets the first message
>> """
>>
>> return open(expanduser(message_filename),
>> 'r').readlines()[index].rstrip()
>>
>> What is more the Python way: let the exception fire like this code
>> when index is to big, or catching it and returning None?
>>
>> I suppose working zero based is OK.
>>
>
> Fire an exception.
>
> One advantage is that the exception will pinpoint exactly which line
> of the function had a problem.

That is what I did. The only ‘problem’ is that they need to catch the
error if they do not know the number of messages in the file. But they
can use get_nr_of_messages for that.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89617

FromPeter Otten <__peter__@web.de>
Date2015-04-30 11:30 +0200
Message-ID<mailman.122.1430386245.3680.python-list@python.org>
In reply to#89610
Cecil Westerhof wrote:

> I have a function to fetch a message from a file:
>     def get_indexed_message(message_filename, index):
>         """
>         Get index message from a file, where 0 gets the first message
>         """
> 
>         return open(expanduser(message_filename),
>         'r').readlines()[index].rstrip()
> 
> What is more the Python way: let the exception fire like this code
> when index is to big, or catching it and returning None?

Fire an exception, but you may also allow the user to provide a default.

> I suppose working zero based is OK.

Not just OK, it's de rigueur. 


You didn't ask for that, but

(1)

with open(...) as f:
    return f.readlines()[index].rstrip()

is preferrable because it closes the file in a controlled way and 

(2) you may want to take measures to limit memory usage, e. g. 

assert index >= 0
try:
    [line] = itertools.islice(f, index, index+1)
except ValueError:
    raise IndexError
return line.rstrip()

[toc] | [prev] | [next] | [standalone]


#89622

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 13:26 +0200
Message-ID<87h9rxx3g6.fsf@Equus.decebal.nl>
In reply to#89617
Op Thursday 30 Apr 2015 11:30 CEST schreef Peter Otten:

> Cecil Westerhof wrote:
>
>> I have a function to fetch a message from a file:
>> def get_indexed_message(message_filename, index):
>> """
>> Get index message from a file, where 0 gets the first message
>> """
>>
>> return open(expanduser(message_filename),
>> 'r').readlines()[index].rstrip()
>>
>> What is more the Python way: let the exception fire like this code
>> when index is to big, or catching it and returning None?
>
> Fire an exception, but you may also allow the user to provide a
> default.
>
>> I suppose working zero based is OK.
>
> Not just OK, it's de rigueur. 
>
>
> You didn't ask for that, but
>
> (1)
>
> with open(...) as f:
> return f.readlines()[index].rstrip()
>
> is preferrable because it closes the file in a controlled way and 

I already did that. In another thread I got to know my assumptions
where wrong.


> (2) you may want to take measures to limit memory usage, e. g. 
>
> assert index >= 0

I put that in, but as first statement.

> try:
> [line] = itertools.islice(f, index, index+1)
> except ValueError:
> raise IndexError
> return line.rstrip()

In my case it is not important. (The biggest file I use has between
100 and 200 lines), but I publish it, so I should do my best to make
it so lean as possible.

To quote a famous comedian: ‘Learning all the time’.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89627

FromPeter Otten <__peter__@web.de>
Date2015-04-30 14:28 +0200
Message-ID<mailman.127.1430396946.3680.python-list@python.org>
In reply to#89622
Cecil Westerhof wrote:

>> (2) you may want to take measures to limit memory usage, e. g.
>>
>> assert index >= 0
> 
> I put that in, but as first statement.

For the record, this was not a recommended check, but rather a way to 
communicate to the reader of my code that unlike yours it doesn't support 
negative indices.
 
>> try:
>>     [line] = itertools.islice(f, index, index+1)
>> except ValueError:
>>     raise IndexError
>> return line.rstrip()
> 
> In my case it is not important. (The biggest file I use has between
> 100 and 200 lines), but I publish it, so I should do my best to make
> it so lean as possible.

If you keep your 

return f.readlines()[index]

anyway you might allow for negative indices, and then

get_indexed_message(message_filename, -1)

fetches the last message in the file and

get_indexed_message(message_filename, slice(None, None))

fetches a list with all messages.

[toc] | [prev] | [next] | [standalone]


#89633

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 16:53 +0200
Message-ID<87sibhvf9k.fsf@Equus.decebal.nl>
In reply to#89627
Op Thursday 30 Apr 2015 14:28 CEST schreef Peter Otten:

> Cecil Westerhof wrote:
>
>>> (2) you may want to take measures to limit memory usage, e. g.
>>>
>>> assert index >= 0
>>
>> I put that in, but as first statement.
>
> For the record, this was not a recommended check, but rather a way
> to communicate to the reader of my code that unlike yours it doesn't
> support negative indices.
>
>>> try:
>>> [line] = itertools.islice(f, index, index+1)
>>> except ValueError:
>>> raise IndexError
>>> return line.rstrip()
>>
>> In my case it is not important. (The biggest file I use has between
>> 100 and 200 lines), but I publish it, so I should do my best to
>> make it so lean as possible.
>
> If you keep your 
>
> return f.readlines()[index]
>
> anyway you might allow for negative indices, and then
>
> get_indexed_message(message_filename, -1)
>
> fetches the last message in the file and
>
> get_indexed_message(message_filename, slice(None, None))
>
> fetches a list with all messages.

It is even possible without keeping it. I can fetch the number of
messages and implement it myself without a possible high memory
overhead. Certainly something to think about.

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89629

FromCecil Westerhof <Cecil@decebal.nl>
Date2015-04-30 14:22 +0200
Message-ID<878ud9x0un.fsf@Equus.decebal.nl>
In reply to#89622
Op Thursday 30 Apr 2015 13:26 CEST schreef Cecil Westerhof:

>> try:
>> [line] = itertools.islice(f, index, index+1)
>> except ValueError:
>> raise IndexError
>> return line.rstrip()
>
> In my case it is not important. (The biggest file I use has between
> 100 and 200 lines), but I publish it, so I should do my best to make
> it so lean as possible.

Implemented and pushed to:
    https://github.com/CecilWesterhof/PythonLibrary/blob/master/filebasedMessages.py

Did some other optimisation's also. The function get_random_message
now calls get_indexed_message. Saves memory (on the old
implementation) and is more DRY.

I also enhanced get_nr_of_messages:
    def get_nr_of_messages(message_filename):
        i = -1
        with open(expanduser(message_filename), 'r') as f:
            for i, l in enumerate(f):
                pass
        return i + 1

Or can that be done better?

-- 
Cecil Westerhof
Senior Software Engineer
LinkedIn: http://www.linkedin.com/in/cecilwesterhof

[toc] | [prev] | [next] | [standalone]


#89626

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-04-30 14:05 +0200
Message-ID<6844153.DioSdhvfDQ@PointedEars.de>
In reply to#89610
Cecil Westerhof wrote:

> I have a function to fetch a message from a file:
>     def get_indexed_message(message_filename, index):
>         """
>         Get index message from a file, where 0 gets the first message
>         """
> 
>         return open(expanduser(message_filename),
>         'r').readlines()[index].rstrip()
> 
> What is more the Python way: let the exception fire like this code
> when index is to big, or catching it and returning None?

It is not only the Python way, it is the *correct* way to throw/_raise_ an 
exception if the language allows it.  Think of what “exception” means: there 
is an *exceptional* (not normal) circumstance that causes execution of the 
function/method to stop.

Return values and status values to indicate such errors were used before 
exceptions, and are still used in languages that do not have exceptions.  
But return values only work if you can tell them apart from success values.  
You have only one error condition now.  If you have a different error 
condition in the future, you need a different return value for that to tell 
it apart from the first error condition.  

There comes a point where you are out of new return values for new error 
conditions such that you cannot tell them apart from success values anymore.  
And functions setting status values to refine return values are not 
reentrant.  But you can always throw a different type of exception or the 
same type of exception with a different message.

> I suppose working zero based is OK.

Yes, it is the common approach.

-- 
PointedEars

Twitter: @PointedEars2
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#89628

FromAntoon Pardon <antoon.pardon@rece.vub.ac.be>
Date2015-04-30 14:30 +0200
Message-ID<mailman.128.1430397102.3680.python-list@python.org>
In reply to#89610
Op 30-04-15 om 09:43 schreef Cecil Westerhof:

> I have a function to fetch a message from a file:
>     def get_indexed_message(message_filename, index):
>         """
>         Get index message from a file, where 0 gets the first message
>         """
>
>         return open(expanduser(message_filename), 'r').readlines()[index].rstrip()
>
> What is more the Python way: let the exception fire like this code
> when index is to big, or catching it and returning None?
>
> I suppose working zero based is OK.

I think this is the wrong question. The right question i: What is the
most logical/consistent thing to do, within your project?

There are at least two ways to look at this.

1) Getting too large an index is very similar to getting an index with an empty
line and can be treated as such. In that case you might prefer to return an
empty line.

2) Getting too large an index indicates a problem that can't be handled here. In
that case you should let the exception propagate to where it can be handled.

2a) You view the IndexError as a good diagnostic, nothing more to do.
2b) You view the IndexError as an error specific to the implementation
and want an exception independent of your implementation: catch the
IndexError and raise one you specified yourself.

-- 
Antoon Pardon

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web