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.



--
DaveA
--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to