Re: What's the use of the else in try/except/else?
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?
[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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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?
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