Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #84852 > unrolled thread
| Started by | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| First post | 2015-01-29 15:51 -0700 |
| Last post | 2015-01-31 01:28 +0000 |
| Articles | 14 — 4 participants |
Back to article view | Back to comp.lang.python
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: The Most Diabolical Python Antipattern Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-29 15:51 -0700
Re: The Most Diabolical Python Antipattern Marko Rauhamaa <marko@pacujo.net> - 2015-01-30 08:16 +0200
Re: The Most Diabolical Python Antipattern Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-01-30 08:10 +0000
Re: The Most Diabolical Python Antipattern Marko Rauhamaa <marko@pacujo.net> - 2015-01-30 11:02 +0200
Re: The Most Diabolical Python Antipattern Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-30 02:17 -0700
Re: The Most Diabolical Python Antipattern Marko Rauhamaa <marko@pacujo.net> - 2015-01-30 12:00 +0200
Re: The Most Diabolical Python Antipattern Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-30 08:21 -0700
Re: The Most Diabolical Python Antipattern Marko Rauhamaa <marko@pacujo.net> - 2015-01-30 17:30 +0200
Re: The Most Diabolical Python Antipattern Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-30 08:42 -0700
Re: The Most Diabolical Python Antipattern Marko Rauhamaa <marko@pacujo.net> - 2015-01-30 17:56 +0200
Re: The Most Diabolical Python Antipattern Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-30 09:38 -0700
Re: The Most Diabolical Python Antipattern Chris Angelico <rosuav@gmail.com> - 2015-01-31 02:55 +1100
Re: The Most Diabolical Python Antipattern Ian Kelly <ian.g.kelly@gmail.com> - 2015-01-30 02:11 -0700
Re: The Most Diabolical Python Antipattern Mark Lawrence <breamoreboy@yahoo.co.uk> - 2015-01-31 01:28 +0000
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-01-29 15:51 -0700 |
| Subject | Re: The Most Diabolical Python Antipattern |
| Message-ID | <mailman.18286.1422571931.18130.python-list@python.org> |
On Thu, Jan 29, 2015 at 10:32 AM, Tim Chase <python.list@tim.thechases.com> wrote: > On 2015-01-29 17:17, Mark Lawrence wrote: >> The author is quite clear on his views here >> https://realpython.com/blog/python/the-most-diabolical-python-antipattern/ >> but what do you guys and gals think? > > I just read that earlier today and agree for the most part. The only > exception (pun only partially intended) I've found is in functions > that need to return a defined type. I have one that I call int0() > that is my "give me a freakin' int" function which is something like > > def int0(val): > try: > return int(val) > except: > return 0 > > because I deal with a lot of CSV data from client/vendor that has > blanks, "NULL", "---", and plenty of other rubbish to suggest > something that, for my purposes is really just a 0. > > Yes, I've been stung by it occasionally, but it's not much trouble to > see that I'm getting a 0 some place that should have a value I need > to extract. At least use "except Exception" instead of a bare except. Do you really want things like SystemExit and KeyboardInterrupt to get turned into 0?
[toc] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-01-30 08:16 +0200 |
| Message-ID | <87r3uchjyg.fsf@elektro.pacujo.net> |
| In reply to | #84852 |
Ian Kelly <ian.g.kelly@gmail.com>:
> At least use "except Exception" instead of a bare except. Do you
> really want things like SystemExit and KeyboardInterrupt to get turned
> into 0?
How about:
==============================
try:
do_interesting_stuff()
except ValueError:
try:
log_it()
except:
pass
raise
==============================
Surprisingly this variant could raise an unexpected exception:
==============================
try:
do_interesting_stuff()
except ValueError:
try:
log_it()
finally:
raise
==============================
A Python bug?
Marko
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2015-01-30 08:10 +0000 |
| Message-ID | <mailman.18296.1422605482.18130.python-list@python.org> |
| In reply to | #84863 |
On 30/01/2015 06:16, Marko Rauhamaa wrote: > Ian Kelly <ian.g.kelly@gmail.com>: > >> At least use "except Exception" instead of a bare except. Do you >> really want things like SystemExit and KeyboardInterrupt to get turned >> into 0? > > How about: > > ============================== > try: > do_interesting_stuff() > except ValueError: > try: > log_it() > except: > pass > raise > ============================== > > Surprisingly this variant could raise an unexpected exception: > > ============================== > try: > do_interesting_stuff() > except ValueError: > try: > log_it() > finally: > raise > ============================== > > A Python bug? > > > Marko > It depends on the Python version that you're running - I think!!! See https://www.python.org/dev/peps/pep-3134/ https://www.python.org/dev/peps/pep-0409/ https://www.python.org/dev/peps/pep-0415/ and finally try (groan :) https://pypi.python.org/pypi/pep3134/ -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-01-30 11:02 +0200 |
| Message-ID | <87r3ucljyv.fsf@elektro.pacujo.net> |
| In reply to | #84867 |
Mark Lawrence <breamoreboy@yahoo.co.uk>: > On 30/01/2015 06:16, Marko Rauhamaa wrote: >> How about: >> >> ============================== >> try: >> do_interesting_stuff() >> except ValueError: >> try: >> log_it() >> except: >> pass >> raise >> ============================== >> >> Surprisingly this variant could raise an unexpected exception: >> >> ============================== >> try: >> do_interesting_stuff() >> except ValueError: >> try: >> log_it() >> finally: >> raise >> ============================== >> >> A Python bug? > > It depends on the Python version that you're running - I think!!! See > https://www.python.org/dev/peps/pep-3134/ TL;DR My Python did do exception chaining, but the problem is the surface exception changes, which could throw off the whole error recovery. So I'm thinking I might have found a valid use case for the "diabolical antipattern." Marko
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-01-30 02:17 -0700 |
| Message-ID | <mailman.18300.1422609481.18130.python-list@python.org> |
| In reply to | #84869 |
On Fri, Jan 30, 2015 at 2:02 AM, Marko Rauhamaa <marko@pacujo.net> wrote: > Mark Lawrence <breamoreboy@yahoo.co.uk>: > >> On 30/01/2015 06:16, Marko Rauhamaa wrote: >>> How about: >>> >>> ============================== >>> try: >>> do_interesting_stuff() >>> except ValueError: >>> try: >>> log_it() >>> except: >>> pass >>> raise >>> ============================== >>> >>> Surprisingly this variant could raise an unexpected exception: >>> >>> ============================== >>> try: >>> do_interesting_stuff() >>> except ValueError: >>> try: >>> log_it() >>> finally: >>> raise >>> ============================== >>> >>> A Python bug? >> >> It depends on the Python version that you're running - I think!!! See >> https://www.python.org/dev/peps/pep-3134/ > > TL;DR > > My Python did do exception chaining, but the problem is the surface > exception changes, which could throw off the whole error recovery. > > So I'm thinking I might have found a valid use case for the "diabolical > antipattern." I suppose, although it seems awfully contrived to me. In any case it would still be better with "except Exception" rather than the bare except. Unless re-raising that ValueError is more important to you than letting the user hit Ctrl-C during the logging call.
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-01-30 12:00 +0200 |
| Message-ID | <87fvaslh9h.fsf@elektro.pacujo.net> |
| In reply to | #84869 |
Marko Rauhamaa <marko@pacujo.net>:
>>> Surprisingly this variant could raise an unexpected exception:
>>>
>>> ==============================
>>> try:
>>> do_interesting_stuff()
>>> except ValueError:
>>> try:
>>> log_it()
>>> finally:
>>> raise
>>> ==============================
>>>
>>> A Python bug?
> [...]
> My Python did do exception chaining, but the problem is the surface
> exception changes, which could throw off the whole error recovery.
BTW, the code above can be fixed:
==============================
try:
do_interesting_stuff()
except ValueError as e:
try:
log_it()
finally:
raise e
==============================
Now the surface exception is kept and the subsidiary exception is
chained to it.
I'm a bit baffled why the two pieces of code are not equivalent.
Marko
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-01-30 08:21 -0700 |
| Message-ID | <mailman.18306.1422631319.18130.python-list@python.org> |
| In reply to | #84874 |
On Fri, Jan 30, 2015 at 3:00 AM, Marko Rauhamaa <marko@pacujo.net> wrote: > Marko Rauhamaa <marko@pacujo.net>: > >>>> Surprisingly this variant could raise an unexpected exception: >>>> >>>> ============================== >>>> try: >>>> do_interesting_stuff() >>>> except ValueError: >>>> try: >>>> log_it() >>>> finally: >>>> raise >>>> ============================== >>>> >>>> A Python bug? >> [...] >> My Python did do exception chaining, but the problem is the surface >> exception changes, which could throw off the whole error recovery. > > BTW, the code above can be fixed: > > ============================== > try: > do_interesting_stuff() > except ValueError as e: > try: > log_it() > finally: > raise e > ============================== > > Now the surface exception is kept and the subsidiary exception is > chained to it. > > I'm a bit baffled why the two pieces of code are not equivalent. The bare raise re-raises the most recent exception that is being handled. The "raise e" raises that exception specifically, which is not the most recent in the case of a secondary exception. Note that the exceptions are actually chained *in reverse*; the message falsely indicates that the secondary exception was raised first, and the primary exception was raised while handling it, e.g.: Traceback (most recent call last): File "<stdin>", line 5, in <module> TypeError During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 7, in <module> File "<stdin>", line 2, in <module> ValueError That's because "raise e" causes the exception e to be freshly raised, whereas the bare "raise" merely makes the existing exception context active again. It's interesting to note here that although the exception retains its original traceback information (note the two separate lines in the traceback), it is not chained again from the TypeError. One might expect to actually see the ValueError, followed by the TypeError, followed by the ValueError in the chain. That doesn't happen because the two ValueErrors raised are actually the same object, and Python is apparently wise enough to break the chain to avoid an infinite cycle.
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-01-30 17:30 +0200 |
| Message-ID | <87zj90jngf.fsf@elektro.pacujo.net> |
| In reply to | #84891 |
Ian Kelly <ian.g.kelly@gmail.com>: > The bare raise re-raises the most recent exception that is being > handled. The "raise e" raises that exception specifically, which is > not the most recent in the case of a secondary exception. Scary. That affects all finally clauses. Must remember that. The pitfall is avoided by using the "except: pass" antipattern but then you lose exception chaining. Marko
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-01-30 08:42 -0700 |
| Message-ID | <mailman.18307.1422632572.18130.python-list@python.org> |
| In reply to | #84892 |
On Fri, Jan 30, 2015 at 8:30 AM, Marko Rauhamaa <marko@pacujo.net> wrote: > Ian Kelly <ian.g.kelly@gmail.com>: > >> The bare raise re-raises the most recent exception that is being >> handled. The "raise e" raises that exception specifically, which is >> not the most recent in the case of a secondary exception. > > Scary. That affects all finally clauses. Must remember that. > > The pitfall is avoided by using the "except: pass" antipattern but then > you lose exception chaining. Like I suggested earlier, just don't catch the inner exception at all. The result will be both exceptions propagated, chained in the proper order.
[toc] | [prev] | [next] | [standalone]
| From | Marko Rauhamaa <marko@pacujo.net> |
|---|---|
| Date | 2015-01-30 17:56 +0200 |
| Message-ID | <87vbjojm86.fsf@elektro.pacujo.net> |
| In reply to | #84893 |
Ian Kelly <ian.g.kelly@gmail.com>: > Like I suggested earlier, just don't catch the inner exception at all. > The result will be both exceptions propagated, chained in the proper > order. Depends on the situation. Marko
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-01-30 09:38 -0700 |
| Message-ID | <mailman.18312.1422635977.18130.python-list@python.org> |
| In reply to | #84896 |
On Fri, Jan 30, 2015 at 8:56 AM, Marko Rauhamaa <marko@pacujo.net> wrote:
> Ian Kelly <ian.g.kelly@gmail.com>:
>
>> Like I suggested earlier, just don't catch the inner exception at all.
>> The result will be both exceptions propagated, chained in the proper
>> order.
>
> Depends on the situation.
Like what? If you want to specifically propagate the original
exception in order to be caught again elsewhere, then I think there's
a code smell to that. If this inner exception handler doesn't
specifically know how to handle a ValueError, then why should some
outer exception handler be able to handle an exception that could have
come from virtually anywhere?
A better approach to that would be to create a specific exception
class that narrowly identifies what went wrong, and raise *that* with
the other exceptions chained to it. E.g.:
try:
do_interesting_stuff()
except ValueError as e:
try:
log_it()
except Exception:
# Chain both exceptions as __context__
raise SpecificException
else:
# Chain the original exception as __cause__
raise SpecificException from e
Or if you don't care about distinguishing __cause__ from __context__:
try:
do_interesting_stuff()
except ValueError:
try:
log_it()
finally:
raise SpecificException
[toc] | [prev] | [next] | [standalone]
| From | Chris Angelico <rosuav@gmail.com> |
|---|---|
| Date | 2015-01-31 02:55 +1100 |
| Message-ID | <mailman.18309.1422633366.18130.python-list@python.org> |
| In reply to | #84892 |
On Sat, Jan 31, 2015 at 2:42 AM, Ian Kelly <ian.g.kelly@gmail.com> wrote: > Like I suggested earlier, just don't catch the inner exception at all. > The result will be both exceptions propagated, chained in the proper > order. So many MANY times, the best thing to do with unrecognized exceptions is simply to not catch them. ChrisA
[toc] | [prev] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2015-01-30 02:11 -0700 |
| Message-ID | <mailman.18299.1422609145.18130.python-list@python.org> |
| In reply to | #84863 |
On Thu, Jan 29, 2015 at 11:16 PM, Marko Rauhamaa <marko@pacujo.net> wrote: > Ian Kelly <ian.g.kelly@gmail.com>: > >> At least use "except Exception" instead of a bare except. Do you >> really want things like SystemExit and KeyboardInterrupt to get turned >> into 0? > > How about: > > ============================== > try: > do_interesting_stuff() > except ValueError: > try: > log_it() > except: > pass > raise > ============================== Are you asking if I think this is better? It still swallows arbitrary exceptions. Why would you want to re-raise the anticipated (and logged) ValueError instead of the exception that could potentially be unexpected? > Surprisingly this variant could raise an unexpected exception: > > ============================== > try: > do_interesting_stuff() > except ValueError: > try: > log_it() > finally: > raise > ============================== > > A Python bug? This does what it is supposed to. "If no expressions are present, raise re-raises the last exception that was active in the current scope." In this case, what that exception is depends on whether the finally clause was entered as a result of an exception or fall-through from the try clause. If you only want to re-raise the ValueError, then use the first form above. If you only want to re-raise the other exception, then do so from an except block (or don't catch it in the first place).
[toc] | [prev] | [next] | [standalone]
| From | Mark Lawrence <breamoreboy@yahoo.co.uk> |
|---|---|
| Date | 2015-01-31 01:28 +0000 |
| Message-ID | <mailman.18325.1422667744.18130.python-list@python.org> |
| In reply to | #84863 |
On 30/01/2015 08:10, Mark Lawrence wrote: > On 30/01/2015 06:16, Marko Rauhamaa wrote: >> Ian Kelly <ian.g.kelly@gmail.com>: >> >>> At least use "except Exception" instead of a bare except. Do you >>> really want things like SystemExit and KeyboardInterrupt to get turned >>> into 0? >> >> How about: >> >> ============================== >> try: >> do_interesting_stuff() >> except ValueError: >> try: >> log_it() >> except: >> pass >> raise >> ============================== >> >> Surprisingly this variant could raise an unexpected exception: >> >> ============================== >> try: >> do_interesting_stuff() >> except ValueError: >> try: >> log_it() >> finally: >> raise >> ============================== >> >> A Python bug? >> >> >> Marko >> > > It depends on the Python version that you're running - I think!!! See > https://www.python.org/dev/peps/pep-3134/ > https://www.python.org/dev/peps/pep-0409/ > https://www.python.org/dev/peps/pep-0415/ and finally try (groan :) > https://pypi.python.org/pypi/pep3134/ > http://bugs.python.org/issue23353 looks like fun and references PEP3134 for anybody who's interested. -- My fellow Pythonistas, ask not what our language can do for you, ask what you can do for our language. Mark Lawrence
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web