Re: What's the use of the else in try/except/else?

2009-05-22 Thread Lawrence D'Oliveiro
In message <8dc983db-b8c4-4897-
a58b-969ca5f8e...@g20g2000vba.googlegroups.com>, Beni Cherniavsky wrote:

> And yes, it's icky - not because of the ``else`` but because
> aquisition-release done correctly is always an icky pattern.

Only in the presence of exceptions.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-17 Thread Beni Cherniavsky
[Long mail.  You may skip to the last paragraph to get the summary.]

On May 12, 12:35 pm, Steven D'Aprano wrote:
> To really be safe, that should become:
>
> try:
>     rsrc = get(resource)
> except ResourceError:
>     log('no more resources available')
>     raise
> else:
>     try:
>         do_something_with(rsrc)
>     finally:
>         rsrc.close()
>
> which is now starting to get a bit icky (but only a bit, and only because
> of the nesting, not because of the else).
>
Note that this example doesn't need ``else``, because the ``except``
clause re-raises the exception.  It could as well be::

try:
rsrc = get(resource)
except ResourceError:
log('no more resources available')
raise
try:
do_something_with(rsrc)
finally:
rsrc.close()

``else`` is relevant only if your ``except`` clause(s) may quietly
suppress the exception::

try:
rsrc = get(resource)
except ResourceError:
log('no more resources available, skipping do_something')
else:
try:
do_something_with(rsrc)
finally:
rsrc.close()

And yes, it's icky - not because of the ``else`` but because
aquisition-release done correctly is always an icky pattern.  That's
why we now have the ``with`` statement - assuming `get()` implements a
context manager, you should be able to write::

with get(resource) as rsrc:
do_something_with(rsrc)

But wait, what if get() fails?  We get an exception!  We wanted to
suppress it::

try:
with get(resource) as rsrc:
do_something_with(rsrc)
except ResourceError:
log('no more resources available, skipping do_something')

But wait, that catches ResourceError in ``do_something_with(rsrc)`` as
well!  Which is precisely what we tried to avoid by using
``try..else``!
Sadly, ``with`` doesn't have an else clause.  If somebody really
believes it should support this pattern, feel free to write a PEP.

I think this is a bad example of ``try..else``.  First, why would you
silently suppress out-of-resource exceptions?  If you don't suppress
them, you don't need ``else``.  Second, such runtime problems are
normally handled uniformely at some high level (log / abort / show a
message box / etc.), wherever they occur - if ``do_something_with(rsrc)
`` raises `ResourceError` you'd want it handled the same way.

So here is another, more practical example of ``try..else``:

try:
bar = foo.get_bar()
except AttributeError:
quux = foo.get_quux()
else:
quux = bar.get_quux()

assuming ``foo.get_bar()`` is optional but ``bar.get_quux()`` isn't.
If we had put ``bar.get_quux()`` inside the ``try``, it could mask a
bug.  In fact to be precise, we don't want to catch an AttributeError
that may happen during the call to ``get_bar()``, so we should move
the call into the ``else``::

try:
get_bar = foo.get_bar
except AttributeError:
quux = foo.get_quux()
else:
quux = get_bar().get_quux()

Ick!

The astute reader will notice that cases where it's important to
localize exception catching involves frequent excetions like
`AttributeError` or `IndexError` -- and that these cases are already
handled by `getattr` and `dict.get` (courtesy of Guido's Time
Machine).

Bottom line(s):
1. ``try..except..else`` is syntactically needed only when ``except``
might suppress the exception.
2. Minimal scope of ``try..except`` doesn't always apply (for
`AttirbuteError` it probably does, for `MemoryError` it probably
doesn't).
3. It *is* somewhat ackward to use, which is why the important use
cases - exceptions that are frequently raised and caught - deserve
wrapping by functions like `getattr()` with default arguments.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-14 Thread Andre Engels
On Thu, May 14, 2009 at 6:39 AM, ma  wrote:
> A really great use for try/except/else would be if an object is
> implementing its own __getitem__ method, so you would have something
> like this:
>
> class SomeObj(object):
>    def __getitem__(self, key):
>                try:
>                        #sometype of assertion here based on key type
>                except AssertionError, e:
>                        raise TypeError, e #invalid type
>                else:
>                        #continue processing, etc.. return some index, which 
> will auto throw
>                        #an index error if you have some type of indexable 
> datastructure

Again, this is a case where no else is needed. Whenever you raise
something in the except clause (as your only exit point), it would
work just as well (though it might be a bit uglier) to put the rest
after the try ... except without an else. It is when after the
exception execution continues normally, but skipping part of the code,
that you need an else.


-- 
André Engels, andreeng...@gmail.com
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-13 Thread ma
That's great to know! Thanks for that explanation, I am refactoring
something and I was going to make ample use of assertion as I thought
it was the same as C's assertion without the NDEBUG flag.


On Thu, May 14, 2009 at 1:03 AM, Steven D'Aprano
 wrote:
> On Thu, 14 May 2009 00:39:35 -0400, ma wrote:
>
>> A really great use for try/except/else would be if an object is
>> implementing its own __getitem__ method, so you would have something
>> like this:
>>
>> class SomeObj(object):
>>     def __getitem__(self, key):
>>               try:
>>                       #sometype of assertion here based on key type
>>               except AssertionError, e:
>>                       raise TypeError, e #invalid type
>
> Why raise AssertionError only to catch it and raise TypeError? Why not
> just raise TypeError in the first place?
>
>
> If you're thinking of writing this:
>
> assert isinstance(key, whatever)
>
> you should be aware that when Python is run with the -O flag (optimize),
> all asserts are disabled, and so your error checking code will not run
> and your program will crash and burn in a horrible flaming mess.
>
>
> [st...@wow-wow ~]$ python -O
> Python 2.5 (r25:51908, Nov  6 2007, 16:54:01)
> [GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
> Type "help", "copyright", "credits" or "license" for more information.
 assert None is 2


>
>
> The assert statement is not for runtime error checking. assert is for
> checking your program logic and invariants. If you've ever written a
> comment like:
>
> # When we get here, then x will always be greater than 3.
>
> (or something like that), that's a great candidate for an assertion:
>
> assert x > 3, "x is unexpectedly less than or equal to three"
>
>
> For error checking, you should do something like this:
>
> if not isinstance(key, whatever):
>    raise ValueError
>
> rather than:
>
> try:
>    if not isinstance(key, whatever):
>        raise AssertionError
> except AssertionError:
>    raise ValueError
>
>
>
>
> --
> Steven
> --
> http://mail.python.org/mailman/listinfo/python-list
>
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-13 Thread Steven D'Aprano
On Thu, 14 May 2009 00:39:35 -0400, ma wrote:

> A really great use for try/except/else would be if an object is
> implementing its own __getitem__ method, so you would have something
> like this:
> 
> class SomeObj(object):
> def __getitem__(self, key):
>   try:
>   #sometype of assertion here based on key type
>   except AssertionError, e:
>   raise TypeError, e #invalid type

Why raise AssertionError only to catch it and raise TypeError? Why not 
just raise TypeError in the first place?


If you're thinking of writing this:

assert isinstance(key, whatever)

you should be aware that when Python is run with the -O flag (optimize), 
all asserts are disabled, and so your error checking code will not run 
and your program will crash and burn in a horrible flaming mess.


[st...@wow-wow ~]$ python -O
Python 2.5 (r25:51908, Nov  6 2007, 16:54:01)
[GCC 4.1.2 20070925 (Red Hat 4.1.2-27)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> assert None is 2
>>>
>>>


The assert statement is not for runtime error checking. assert is for 
checking your program logic and invariants. If you've ever written a 
comment like:

# When we get here, then x will always be greater than 3.

(or something like that), that's a great candidate for an assertion:

assert x > 3, "x is unexpectedly less than or equal to three"


For error checking, you should do something like this:

if not isinstance(key, whatever):
raise ValueError

rather than:

try:
if not isinstance(key, whatever):
raise AssertionError
except AssertionError:
raise ValueError




-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-13 Thread ma
A really great use for try/except/else would be if an object is
implementing its own __getitem__ method, so you would have something
like this:

class SomeObj(object):
def __getitem__(self, key):
try:
#sometype of assertion here based on key type
except AssertionError, e:
raise TypeError, e #invalid type
else:
#continue processing, etc.. return some index, which 
will auto throw
#an index error if you have some type of indexable 
datastructure
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-13 Thread Steven D'Aprano
On Wed, 13 May 2009 20:44:27 +1200, Lawrence D'Oliveiro wrote:

> In message ,
> Steven D'Aprano wrote:
> 
>> On Tue, 12 May 2009 09:20:36 +, Steven D'Aprano wrote:
>>
>>> It seems pretty straightforward to me.
>> 
>> Except of course such a pattern won't work ...
> 
> I rest my case.

Gosh, with such shallowness of analysis and out-of-context quoting, how 
could I possibly disagree? You've convinced me utterly.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-13 Thread Scott David Daniels

greg wrote:

kj wrote:


Wow.  As rationales for syntax constructs go, this has got to be
the most subtle one I've ever seen...


It's to avoid masking bugs. Suppose you accidentally
wrote

  try:
v = mumble.field
sys.warming('field was actually there?')
  except AttributeError:
pass

Then you could easily fail to notice that
you had written 'warming' instead of 'warning'.


Well, if you look, you'll discover that warning is not in the
sys module at all, but in the logging module.
So the original example already demonstrated the problem.

--Scott David Daniels
scott.dani...@acm.org
--
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-13 Thread Lawrence D'Oliveiro
In message , Steven 
D'Aprano wrote:

> On Tue, 12 May 2009 09:20:36 +, Steven D'Aprano wrote:
>
>> It seems pretty straightforward to me.
> 
> Except of course such a pattern won't work ...

I rest my case.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-12 Thread greg

kj wrote:


Wow.  As rationales for syntax constructs go, this has got to be
the most subtle one I've ever seen...


It's to avoid masking bugs. Suppose you accidentally
wrote

  try:
v = mumble.field
sys.warming('field was actually there?')
  except AttributeError:
pass

Then you could easily fail to notice that
you had written 'warming' instead of 'warning'.

--
Greg
--
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-12 Thread Carl Banks
On May 12, 2:35 am, Steven D'Aprano
 wrote:
> On Tue, 12 May 2009 09:20:36 +, Steven D'Aprano wrote:
> > On Tue, 12 May 2009 20:23:25 +1200, Lawrence D'Oliveiro wrote:
>
> >> In message , kj wrote:
>
> >>> I know about the construct:
>
> >>> try:
> >>>     # do something
> >>> except ...:
> >>>     # handle exception
> >>> else:
> >>>     # do something else
>
> >>> ...but I can't come with an example in which the same couldn't be
> >>> accomplished with [no else]
>
> >> I'd agree. If you have to resort to a "try .. else", then might I
> >> respectfully suggest that you're using exceptions in a way that's
> >> complicated enough to get you into trouble.
>
> > try:
> >     rsrc = get(resource)
> > except ResourceError:
> >     log('no more resources available')
> >     raise
> > else:
> >     do_something_with(rsrc)
> > finally:
> >     rsrc.close()
>
> Except of course such a pattern won't work, because if get(resource)
> fails, rsrc will not exist to be closed. So a better, and simpler,
> example would be to drop the finally clause:

Resource acquisition goes outside the try block.  If you want to log
an error, then get() goes inside its own try block.

try:
rsrc = get(resource)
except ResourceError:
log('no more resources available')
raise
try:
do_something_with(rsrc)
finally:
rsrc.close()


If you hadn't reraised the exception, then the else clause would have
been useful as follows:

try:
rsrc = get(resource)
except ResourceError:
proceed_without_resource()
else:
try:
proceed_with_resource()
# Note: proceed_with_resource() can possibly raise
# ResourceError itself
finally:
rsrc.close()

The main reason for the else clause on try blocks is so that you don't
risk catching spurrious exceptions.  You could stick
proceed_with_resource() in the try clause, but then if
proceed_with_resource() throws ResourceError because it tries to
acquire a different resource and fails, then it'd be caught and
proceed_without_resource() would be called, which is a mistake.

In general, you want to limit the contents of a try clause to code
that throws an exception you want to catch (if you're trying to catch
an exception); everything else should go into the else clause.

Incidentally, I can't think of any realistic use cases for using all
four of try...except...else...finally.


Carl Banks
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-12 Thread Peter Pearson
On 12 May 2009 09:35:36 GMT, Steven D'Aprano wrote:
[snip]
> To really be safe, that should become:
>
> try:
> rsrc = get(resource)
> except ResourceError:
> log('no more resources available')
> raise
> else:
> try:
> do_something_with(rsrc)
> finally:
> rsrc.close()

Thanks, Steven.  I find these examples illuminating.

Not trying to be dense, but given that the "except" block
re-raises the exception, isn't the above the same as . . .?

try:
rsrc = get(resource)
except ResourceError:
log('no more resources available')
raise
try:
do_something_with(rsrc)
finally:
rsrc.close()

-- 
To email me, substitute nowhere->spamcop, invalid->net.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-12 Thread Steven D'Aprano
On Tue, 12 May 2009 09:20:36 +, Steven D'Aprano wrote:

> On Tue, 12 May 2009 20:23:25 +1200, Lawrence D'Oliveiro wrote:
> 
>> In message , kj wrote:
>> 
>>> I know about the construct:
>>> 
>>> try:
>>> # do something
>>> except ...:
>>> # handle exception
>>> else:
>>> # do something else
>>> 
>>> ...but I can't come with an example in which the same couldn't be
>>> accomplished with [no else]
>> 
>> I'd agree. If you have to resort to a "try .. else", then might I
>> respectfully suggest that you're using exceptions in a way that's
>> complicated enough to get you into trouble.
> 
> 
> 
> try:
> rsrc = get(resource)
> except ResourceError:
> log('no more resources available')
> raise
> else:
> do_something_with(rsrc)
> finally:
> rsrc.close()



Except of course such a pattern won't work, because if get(resource) 
fails, rsrc will not exist to be closed. So a better, and simpler, 
example would be to drop the finally clause:

try:
rsrc = get(resource)
except ResourceError:
log('no more resources available')
raise
else:
do_something_with(rsrc)
rsrc.close()


To really be safe, that should become:

try:
rsrc = get(resource)
except ResourceError:
log('no more resources available')
raise
else:
try:
do_something_with(rsrc)
finally:
rsrc.close()


which is now starting to get a bit icky (but only a bit, and only because 
of the nesting, not because of the else).



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-12 Thread Steven D'Aprano
On Tue, 12 May 2009 20:23:25 +1200, Lawrence D'Oliveiro wrote:

> In message , kj wrote:
> 
>> I know about the construct:
>> 
>> try:
>> # do something
>> except ...:
>> # handle exception
>> else:
>> # do something else
>> 
>> ...but I can't come with an example in which the same couldn't be
>> accomplished with [no else]
> 
> I'd agree. If you have to resort to a "try .. else", then might I
> respectfully suggest that you're using exceptions in a way that's
> complicated enough to get you into trouble.



try:
rsrc = get(resource)
except ResourceError:
log('no more resources available')
raise
else:
do_something_with(rsrc)
finally:
rsrc.close()



is complicated? It seems pretty straightforward to me.



-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-12 Thread Lawrence D'Oliveiro
In message , kj wrote:

> I know about the construct:
> 
> try:
> # do something
> except ...:
> # handle exception
> else:
> # do something else
> 
> ...but I can't come with an example in which the same couldn't be
> accomplished with [no else]

I'd agree. If you have to resort to a "try .. else", then might I 
respectfully suggest that you're using exceptions in a way that's 
complicated enough to get you into trouble.

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-11 Thread kj
In  Scott David Daniels 
 writes:

>kj wrote:
>> ...  I can't come with an example in which the same couldn't be
>> accomplished with
>> 
>> try:
>> # do something
>> # do something else
>> except ...:
>> # handle exception
>> 
>> The only significant difference I can come up with is that in the
>> second form, the except clause may be masking some unexpected
>> exceptions from the "do something else" part.  Is this the rationale
>> behind this else clause?  Or is there something more to it?

>Yes, in a way.  The idea of catching particular exceptions is to only
>handle exceptions you expect (let the others go out to more general
>reporters).  So, not only should you choose the tightest exception to
>catch that you can, but you should look for it in a very narrow window:
>exactly where you expect it.

> try:
> v = mumble.field
> except AttributeError:
> pass
> else:
> sys.warning('field was actually there?')

>as opposed to:

> try:
> v = mumble.field
> sys.warning('field was actually there?')
> except AttributeError:
> pass

>The idea is to make it clear what you expect might go
>wrong that you are prepared to handle.

Wow.  As rationales for syntax constructs go, this has got to be
the most subtle one I've ever seen...

Thanks!

kynn

-- 
NOTE: In my address everything before the first period is backwards;
and the last period, and everything after it, should be discarded.
-- 
http://mail.python.org/mailman/listinfo/python-list


Re: What's the use of the else in try/except/else?

2009-05-10 Thread Scott David Daniels

kj wrote:

...  I can't come with an example in which the same couldn't be
accomplished with

try:
# do something
# do something else
except ...:
# handle exception

The only significant difference I can come up with is that in the
second form, the except clause may be masking some unexpected
exceptions from the "do something else" part.  Is this the rationale
behind this else clause?  Or is there something more to it?


Yes, in a way.  The idea of catching particular exceptions is to only
handle exceptions you expect (let the others go out to more general
reporters).  So, not only should you choose the tightest exception to
catch that you can, but you should look for it in a very narrow window:
exactly where you expect it.

try:
v = mumble.field
except AttributeError:
pass
else:
sys.warning('field was actually there?')

as opposed to:

try:
v = mumble.field
sys.warning('field was actually there?')
except AttributeError:
pass

The idea is to make it clear what you expect might go
wrong that you are prepared to handle.

--Scott David Daniels
scott.dani...@acm.org
--
http://mail.python.org/mailman/listinfo/python-list


What's the use of the else in try/except/else?

2009-05-10 Thread kj


I know about the construct:

try:
# do something 
except ...:
# handle exception
else:
# do something else

...but I can't come with an example in which the same couldn't be
accomplished with

try:
# do something
# do something else
except ...:
# handle exception

The only significant difference I can come up with is that in the
second form, the except clause may be masking some unexpected
exceptions from the "do something else" part.  Is this the rationale
behind this else clause?  Or is there something more to it?

TIA!

kynn

-- 
NOTE: In my address everything before the first period is backwards;
and the last period, and everything after it, should be discarded.
--
http://mail.python.org/mailman/listinfo/python-list