5 ms·
I have mixed feelings about this. There are two "problems" this PEP is trying to solve. One is that bare excepts are permitted. The argument against this is t
by williamsmj 2y ago
I have mixed feelings about this.
There are two "problems" this PEP is trying to solve.
One is that bare excepts are permitted. The argument against this is that explicit is better than implicit. A matter of taste, but I don't find this convincing.
The other problem is what bare excepts mean. Bare excepts are syntactic sugar for `except BaseException`. This means that an application containing a bare `except` followed by the vast majority of real-world error handling will continue to run even if SystemExit or KeyboardInterrupt is raised. This is almost always a bug.
I do find this second argument convincing, and I wish Python did not contain this design wart.
If I could go back in time and change Python syntax, it would make it hard for people to silently treat these special interrupts as "handleable" like regular errors. The tiny set of applications that really can and should handle them (e.g. TUIs or the mailman example discussed in the final section of the PEP) can explicitly do so with e.g. `except KeyboardInterrurpt` or even `except BaseException`.
But I agree with the consensus here that this does not rise to the level of something being worth a backwards-incompatible change.
- theamk 2y agoDisagree. I do this kind of code all the time: try: something() except: log_tons_of_debug_info() raise and I am very glad that I get my debug info works even if I press Ctrl-C or someone calls sys.exit().
- bee_rider 2y agoI dunno, this just usually means I’m going to hold control and mash C, hopefully I can get my interrupt to occur inside your except
- rcxdude 2y agoThat's unecessary, because of the 'raise' statement. This construct effectively only hooks exceptions, it doesn't swallow them.
- encoderer 2y agoSignals are non-reentrant.
- theamk 2y agoYou know about Ctrl-\, right? Kills python right away, no exceptions or anything. (there is also coredump but most distros disable or hide them, so it's not a problem in practice)
- williamsmj 2y agoAnyone reading your code is going to assume this is a bug. The PEP is right that explicit is better than implicit. You should write `except BaseException` (whether or not this PEP is approved).
- TuxSH 2y ago"except:" is explicit enough and "except BaseException" is redundant. Moreover I think there is a real risk people are going to write "except Exception:" instead, which breaks in the fringe case an exception that derives from BaseException (enforced by interpreter) but not from Exception is thrown. Even if catch Exception is what users usually mean, changing code from "catch (BaseException):" to "catch Exception:" may break some code if improperly reviewed. It's also not worth breaking production code over this.
- williamsmj 2y ago> "except:" is explicit enough and "except BaseException" is redundant. Take that up with the consensus view of the python community, as reflected by python linters in their default configuration, almost all of which warn on bare except. The debate in the PEP is whether this should be a syntax error. The debate about whether it is good style is over though. > It's also not worth breaking production code over this. Agreed.
- TuxSH 2y ago> Take that up with the consensus view of the python community, as reflected by python linters in their default configuration, almost all of which warn on bare except. I don't fully agree on it being a purely a style issue (though the warnings from linters are wholly justified). From what I understand, "except:" is a code smell because you don't actually want to catch BaseException instead of just Exception. Linters wouldn't have warned about it if it meant "except Exception:". The real issue, IMO, is the fact non-exceptions (Ctrl-C, generator exit, program exit code, etc.) have been crammed into the exception system.
- zahlman 2y ago
- 1st1 2y agoJust noting it here: your code is incorrect. In case of a KeyboardInterrupt error and another error raised by `log_tons_of_debug_info()` (there's no error free code, right?), KeyboardInterrupt would end up being masked (it would go into the __context__ attribute of another error). The program won't abort its execution. And it's just one example out of many where it's critical to not mask error types. Correct code would be: try: something() except BaseException as ex: try: log_tons_of_debug_info() finally: raise ex But really, you don't want to mess with BaseExceptions at all, so just do `except Exception` instead of a bare `except:`.
- theamk 2y agoWhy wouldn't I want to mess with BaseExceptions? They are not magic, and add only 3 classes to the list: SystemExit - You _definitely_ want to catch this one for logging. If a library (not top-level app) calls `sys.exit` you at least want to know what's happening, if anything so you can talk to author and get them to use proper exception types. KeyboardInterrupt - I normally want to catch this one as well. If the program was taking too long and I hit Ctrl-C to stop it, I _do_ want to see all the debug output. And if I don't, for some reason, there is always Ctrl-\ which kills python immediately and unconditionally. GeneratorExit - this one is tricky and I agree that in a lot of cases, you don't want to print logs on it. But it also very rare - it only appears in async functions (emitted by yield), and never propagated to caller. So as long as you are not doing async, you can simply ignore it, which covers majority of the the code I write.
- 1st1 2y agoBecause accidentally masking some BaseExceptions like `asyncio.CancelledError` can lead to things like memory/resource leaks and potentially your production app going down in pretty hard to debug ways.
- theamk 2y agowell, yeah, you don't want to mask any of those. Thats why all my examples talk about logging + re-raising.
- gmueckl 2y agoJava solved the problem by having Throwable as the root of all exceptions and not advertising that fact loudly. The derived Exception class is the root of all safely catchable exceptions. When someone catches a Throwable, something strange is going on.
- williamsmj 2y agoPython does the same thing. It just calls Throwable something different. Java Throwable ~= Python BaseException. Java Exception ~= Python Exception. The problem here is that a bare except catches something similar to Throwable, not something similar to Exception.
- rectang 2y ago> Bare excepts are syntactic sugar for `except BaseException`. I'm guessing that a `3to4` script would be provided which replaces bare `except:` with `except BaseException:`. We have the experience of `2to3` to draw on with regards to how that might play out. EDIT: Haha, I now see that this PEP proposes a change without advancing the major version. That surprises me.
- williamsmj 2y ago1. Such a script is proposed in the PEP. 2. Python does not use semantic versioning. 3.13 is a different major version to 3.12.
- pansa2 2y agoGiven what happened with Python 2 => 3, I’m not sure we’ll ever see Python 4.