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, sohcahto...@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
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to