try..except with empty exceptions

Dave Angel davea at davea.name
Sat Apr 11 06:24:38 EDT 2015


On 04/11/2015 06:14 AM, Dave Angel wrote:
> On 04/11/2015 03:11 AM, Steven D'Aprano wrote:
>> On Sat, 11 Apr 2015 12:23 pm, Dave Angel wrote:
>>
>>> On 04/10/2015 09:42 PM, Steven D'Aprano wrote:
>>>> On Sat, 11 Apr 2015 05:31 am, sohcahtoa82 at gmail.com wrote:
>>>>
>>>>> It isn't document because it is expected.  Why would the exception get
>>>>> caught if you're not writing code to catch it?  If you write a
>>>>> function
>>>>> and pass it a tuple of exceptions to catch, I'm not sure why you would
>>>>> expect it to catch an exception not in the tuple.  Just because the
>>>>> tuple
>>>>> is empty doesn't mean that it should catch *everything* instead.  That
>>>>> would be counter-intuitive.
>>>>
>>>> Really? I have to say, I expected it.
>>>>
>>>>
>>>
>>> I'm astounded at your expectation.  That's like saying a for loop on an
>>> empty list ought to loop on all possible objects in the universe.
>>
>> Not really.
>>
>> If we wrote:
>>
>>      for x in:
>>          # Missing sequence leads to an infinite loop
>>
>> *then* your analogy would be excellent, but it isn't. With for loops, we
>> iterate over each item in the sequence, hence an empty sequence means we
>> don't iterate at all.
>>
>> But with try...except, an empty exception list means to catch
>> *everything*,
>> not nothing:
>
> No an empty exception list means to catch nothing.  A *missing*
> exception list means catch everything, but that's a different syntax
>>
>> try: ...
>> except a,b,c: # catches a, b, c
>>
>> try: ...
>> except a,b: # catches a, b
>>
>> try: ...
>> except a: # catches a
>
> try: ...
> except (a,)   #catches a
>
> try: ...
> except ()  #catches nothing, as expected
>
>>
>> try: ...
>> except: # catches EVERYTHING, not nothing
>>
>
> Different syntax.  No reason for it to pretend that it's being given an
> empty tuple or list.
>
>>
>> Putting (a, b, c) into a tuple shouldn't make a difference, and it
>> doesn't,
>> unless the tuple is empty. That surprised me.
>>
>> t = a, b, c
>> try:
>> except t:  # same as except a,b,c
>>
>> t = a, b
>> try:
>> except t:  # same as except a,b
>>
>> t = a,
>> try:
>> except t:  # same as except a
>>
>> t = ()
>> try:
>> except t:  # NOT THE SAME as bare except.
>
> Of course not.  It's empty, so it catches nothing. Just like 'for'
>
>>
>>
>> I can see the logic behind the current behaviour. If you implement except
>> clauses like this pseudo-code:
>>
>>
>> for exc in exceptions:
>>      if raised_exception matches exc: catch it
>>
>>
>> then an empty tuple will naturally lead to nothing being caught. That
>> doesn't mean it isn't surprising from the perspective that an empty
>> exception list (i.e. a bare except) should be analogous to an empty
>> tuple.
>
> Why should it??  It's a different syntax, with different rules.  Perhaps
> it should have been consistent, but then it's this statement that's
> surprising, not the behavior with an empty tuple.
>
>>
>>
>>> The tuple lists those exceptions you're interested in, and they are
>>> tried, presumably in order, from that collection.  If none of those
>>> match, then the logic will advance to the next except clause.  If the
>>> tuple is empty, then clearly none will match.
>>
>> Yes, that makes sense, and I agree that it is reasonable behaviour
>> from one
>> perspective. But its also reasonable to treat "except ():" as
>> analogous to
>> a bare except.
>>
>> [...]
>>>> try:
>>>>       spam()
>>>> except:
>>>>       # Implicitly an empty tuple.
>>>
>>> No, an omitted item is not the same as an empty tuple.
>>
>> You are correct about Python as it actually is, but it could have been
>> designed so that except (): was equivalent to a bare except.
>
> Only by changing the bare except behavior.
>
>>
>>
>>> If it were, then
>>> we wouldn't have the problem of bare excepts, which are so tempting to
>>> novices.  There's plenty of precedent in many languages for a missing
>>> item being distinct from anything one could actually supply.
>>
>> Let us put aside the fact that some people misuse bare excepts, and allow
>> that there are some uses for it. Now, in Python 2.6 and later, you can
>> catch everything by catching BaseException. But in older versions, you
>> could raise strings as well, and the only way to catch everything is
>> with a
>> bare except.
>>
>> If you want to write a function that takes a list of things to catch,
>> defaulting to "everything", in Python 2.6+ we can write:
>>
>> def spam(things_to_catch=BaseException):
>>      try:
>>          do_stuff()
>>      except things_to_catch:
>>          handle_exception()
>>
>>
>> but in older versions you have to write this:
>>
>> def spam(things_to_catch=None):
>>      if things_to_catch is None:
>>          try:
>>              do_stuff()
>>          except:
>>              handle_exception()
>>      else:
>>          try:
>>              do_stuff()
>>          except things_to_catch:
>>              handle_exception()
>>
>>
>> This violates Don't Repeat Yourself. Any time you have "a missing item
>> being
>> distinct from anything one could actually supply", you have a poor
>> design.
>
> Yep, and it happens all the time.  For example, mylist[a,b,-1]    What
> value can I use for b to mean the whole list?
>
> There are others more grotesque, but I can't think of any at this moment.
>
>>
>> Anyway, in modern Python (2.6 onwards), now that string exceptions are
>> gone,
>> you can supply something to catch everything. Or nothing, for that
>> matter:
>>
>> BaseException  # catch everything
>> Exception  # catch errors
>> (A, B, C)  # Just A, B or C or their subclasses
>> A  # Just A (or its subclasses)
>> ()  # Catch nothing.
>>
>> so I suppose that having an empty tuple mean "catch nothing" is better
>> than
>> having it catch everything.
>>
>
> Just like with all(()) and any(()), there's a logical way and an
> illogical way.  An empty list means no items, not all possible items.
>

A better analogy:

       if  item  in mytuple:
              process...

If mytuple is (), should this somehow turn into the equivalent of
       if   True:

of course not.  If mytuple is an empty tuple, then the if never succeeds.

In this case, just like with the real try/except (before 2.6), if you 
need to effectively make an infinite tuple, so that all possible items 
would match, you'd need different syntax:

      #No syntax needed for this case, we don't care what item is
      process...



-- 
DaveA



More information about the Python-list mailing list