For those Python users for whom writing python is the core of their work that might be fine. For all the other users for whom python is an foreign, incidental, but indispensable part of their work (scientists, analysts, ...) the choice is untenable. While python can and should strive to be a more 'serious', 'professional' language, it _must_ have respect and empathy for the latter camp. Elevating something that should be a linter rule to a language change ain't that.
If these things start happening to python 3 on a larger scale, might as well throw in the towel and go for python 4.
String operations should have bytes and utf-{8,16} versions. The string value would have is_valid_utf_{8,16} flags and operations should unset them if they end up breaking the format (eg str[i] = 0xff would always mark the string as not unicode, str[i] = 0x00 would check if the flag was set and it so check whether the assignment broke a codepoint and unset the flag if so)
Bytes are not strings. Bytes can represent strings, numbers, pointers, absolutely anything.
If you are actually dealing with legacy data, you want your programs to not care about encodings at all.
File names are sequence of bytes... if it's not a valid UTF-8, why would program even care? A C program from 1980 can print "Cannot open file x<ff><ff>.txt" without known what encoding it, why can't Python do this today without lots of hoops? Sure, the terminal might not show this, but user will likely redirect errors to file anyway and use the right tools to view it.
File contents are sequence of bytes. Every national encoding keeps 0-31 range as control characters, and most of them (except systems like Shift-JIS) keep lower half as well. Which means a program should be able to parse .ini file which says "name=<ff><ff>", store <ff><ff> into a string variable, and later print "Parsing section <ff><ff>" to stdout - all without ever knowning which encoding this is.
There are very few operations which _really_ care about encoding (text rendering, case-insensitive matching, column alignment) and they need careful handling and full-blown unicode libraries anyway, with megabytes of data tables. Forcing all other strings to be UTF-8 just for the sake of it is counterproductive and makes national language support much harder.
Sort of like if c was still c90 and compilers mostly had no extensions.
> The Python 3 statement was drawn up around 2016. Projects pledged to require Python 3 by 2020, giving other projects confidence that they could plan a similar transition, and allowing downstream users to figure out their options without a nasty surprise. We didn’t force people to move to Python 3, but if they wanted to stick with Python 2, they would stop getting new versions of our projects.
(https://python3statement.github.io/)
I know this sounds like a joke, and you probably think you're misreading, but no. Projects pledged to require Python 3 by 2020. They made a promise to break backward compatibility. Not just a few minor projects, either; TensorFlow, Spark, IPython, Pandas, NumPy, SymPy, Hypothesis, etc.
Since that happened, everyone who considers backward-compatibility good (if costly), rather than evil, has abandoned Python.
The "other users for whom python is an foreign, incidental, but indispensable part of their work (scientists, analysts, ...)" would have to fork Python, but it's probably too late for that; they can hardly hope to fork TensorFlow, Pandas, etc., as well.
2. To the extent you object to changes in the core language, the python maintainers do have a backwards compatibility statement and prominent timelines for deprecation. You may disagree with these, but they are public.
3. At the time it was written, the python 3 statement proposed dropping support for a version of python with known security problems and no plans for security updates. It seems like your argument is with the python 2 to python 3 transition, which feels like a conversation we've had here before.
My objection is not to library owners dropping support for Python 2, which is a perfectly reasonable choice for them to make—backward compatibility can be costly, after all, and the benefits may not be worth it. My objection is to library owners pledging to drop support for Python 2, because that entails that they think backward compatibility is itself harmful. To me, that's pants-on-head crazy thinking, like not wanting to wear last season's sweater, or not wanting to use JSON because it's too old.
Observably, since this happened, the Python maintainers have been very active at breaking backward compatibility. (And there's substantial overlap between Python maintainers and major Python library maintainers, which I suspect explains the motivation.) I think this is probably due to people who don't think backward compatibility is actually evil (the aforementioned "all the other users for whom python is an foreign, incidental, but indispensable part of their work") fleeing Python for ecosystems like Node, Golang, and Rust. This eliminates the constituency for maintaining backward compatibility.
I do think the botched 2→3 transition was probably the wellspring of this dysfunction, but I don't think that in itself it was necessarily a bad idea, just executed badly.
As a result of this mess, it's usually easy for me to run Lisp code from 40 years ago, C code from 30 years ago, or Perl or JS code from 20 years ago, but so difficult to run most Python code from 5 years ago as to be impractical.
In fact, the consensus was so strongly against it that it has already been withdrawn.
Basically you've been a guest long enough and now the towels, entertainment, and snacks are going away. If this appears blunt it is pretty obvious why bluntness is required anything else asks for a decade of free support given by inched at the expense of more laudible goals.
Your comment would be correct if we were discussing a lack of continued support for Python 2, or even a public announcement of a planned cessation of such support. But we're discussing a public promise to break support for Python 2, in the form of a petition seeking more signatories. Although the difference may be too subtle for you to have noticed, it's an entirely different animal. It's like the difference between hotels that don't promise you a room that allows smoking, and hotels that promise you a room that doesn't allow smoking. The second case is a promise to keep your room free of the nauseating stench of Python 2.
But what user would want that? Why would you prefer a language or a library that promises to break backward compatibility? What's the benefit to you of the language making your code cease to function every year or two? Job security, perhaps?
I suspect anyone willing to pay enough could get support for whatever they please and with enthusiasm.
> But what user would want that?
Python has existed for 35 years. Every ecosystem decades old that hasn't entirely ossified has undergone change that required work. People don't want change but they want the end result. Your entitled to your own time, feelings, and opinions but nobody wronged you if the people who actually did the work adjudged differently. The work they did is the only justification required. Eating someone else's sandwich isn't a favor to them and it doesn't entitle you to privileges in their kitchen.
> intent to publicly shame...But we're discussing a public promise to break support for Python 2...break...nauseating stench of Python 2..
They collaborated in making the decision to make a clean break from python 2 after 12-16 years of moving in that direction because it was a reasonable technical decision. All this editorializing is like watching someone relive the stages of grief as it applies to the death of other's willingness to do free labor for them. Like a technical manual as read by soap opera stars to exaggerated effect.
There is no loss. Nobody died. Nobody lost anything to which they were entitled. All that open source code that existed is still there. You were never owed new python2 versions of other people's libraries. Either enjoy the old or ring in the new and be glad that so many continue to spend so much time both then and now giving you so many gifts. Count your blessings instead of lamenting the cost of change.
[1]: depending on if we count 3.0 vs 3.2 when it was actually kinda usable.
In the doc you linked, they reference "major" and "minor" versions. So they claim to have some concept of version numbers having different significance... Why don't they adhere to semantic versioning if they dress their version numbers like that?
At least Linux just admits their X.Y scheme means nothing.
from __future__ import no_bare_except
...and enjoy.I guess that __future__ is doing something similar, but I am thinking of something like declaring how options should be set for your module and then only the code in that module is affected. (It would be nice being able to set constraints on what options your dependencies can enable)
I guess that for std functionality this is impossible (like if the dict changed its key sorting it might be too hard to dispatch on the original file) but for syntax it should be perfectly possible.
That being said, as far as workplace differences I’d say Java shops would be the ideal, slower, less long term problems but so much more initial investment.
I’m on the fence about Go, but maybe that’s my preference to having classes.
But yeah I’m the general case if I was an investor I’d be more careful with purely Python based startups.
Python doesn't enforce types and as far as I know has no plans to.
> .Net doesn’t really match with startup culture.
Who the hell cares? If it's the best tool for the job, use it. Anything else is unprofessional as hell.
If I want to learn .Net which is more time consuming and more difficult to find employees why would I use it? Makes sense if you are in an area with a lot of windows people, but that’s not the case anywhere other than Texas.
And the compiler enforce typing. Admittedly not as nice as Go since you have to rely on external tools but workable.
People like their curly brackets though. Just not as helpful when dealing with system problems.
There is a good chance something else might be going on in one of the dependencies or perhaps some other infra package a team maintains, that slows this down. Sometimes teams publish SDK images on accident that have to be pulled over the network if they got evicted from the node cache, or try to use self-contained instead of runtime image + plain application - I know at least two cases where this was causing worse than desired deployment speed on GKE (arguably GKE is as much at fault here, but that's another topic).
I don’t understand the idiomatic viewpoint either here, I understand the author personally finds it confusing when excepts aren’t verbose but I think you would be hard pressed to find many python developers who agree. Even outside the ecosystem, most languages have been adding more support for bare excepts (like js with bare catch) so this feels like a step backwards.
But maybe I’m just not understanding this proposal!
To me it stinks of an ego-centric person thinking they're a "language developer" and knowing better than the actual users of the language what's best for them. Just because something can be misused doesn't mean you have to take it away.
I haven't noticed, but since Rust came along is there a trend among languages to enforce "safer" programming at the language level? I could see that kind of thinking getting way out of hand. If that's the case, I would see this one as "I'm going to save the world with this dumb little change that breaks things for a bunch of people!"
I would hope a PEP like this came about from frequent user requests but that doesn't seem to be the case.
In 2016, you could call your function `fn async(...) { ... }` without any issues, and you can still compile this code with the modern version of rustc. If you want to use the async features of Rust, you need to change your edition to at least 2018, which brings breaking changes in the language.
And you can have a project that mixes those editions, and cargo will correctly use the edition asked for each crate.
(So, I guess the ideal world would to first look at the package management in Python, and *then* try to introduce breaking changes. And I'm withholding how much I'm angry at the PSF for postponing having a decent package manager for 20 years and investing in removing the GIL and adding JIT.)
All the more reason to take a breakage very seriously. This is even worse than the walrus operator. At least I can ignore that. This breaks working code for some notion of purity.
I mentioned Rust because the memory safety guarantees are a significant new thing for a language like that. I forgot about "managed" languages like C# because that's quite far from my mind, but that's another significant attempt at safety. This kind of little detail in the PIP is really insignificant by comparison, so I was speculating that it might be driven by some kind of "save everyone" mentality. If so, wondering if that's a trend lately and I hadn't noticed.
That's why I put "language developer" in quotes.
[0] https://en.wikipedia.org/wiki/Object-Oriented_Software_Const...
so that people can opt-in or opt-out selectively, per their own discretion, for these kinds of rules
I dont see the point of this being part of the language since it break compat and brings zero benefits at runtime
It's the enforcement by compiler, which will break lots of existing code, that makes people unhappy.
I'm hoping Python 4 will be a big breaking change similar to the previous one and full support for explicit types will be one of the reasons.
Edit: I don't get the hate for "i" or "j" as increment variables. When you're working with numerical data they closely match how you would express the same operation with mathematical notation and are idiomatic to the point that everyone with non-trivial experience in programming knows what they represent. There are better options in some cases (e.g. "for name in names:"), but there's nothing inherently wrong with i, j, k, etc.
Most people just renamed variables like i > ii, which was worse.
For example: https://clang.llvm.org/extra/clang-tidy/checks/readability/i...
I flag nearly all abbreviations in code reviews because code is meant to be read and the names of things should be clear.
Upsides: consistent vocabulary in your project, a centralized place to look up jargon, and a subtle friction to avoid adding new terms that people might not immediately grok.
I wish I could remember the source; because it sounded like a nice setup to steal.
* x, y, z (coordinates)
* r, g, b, a; c, m, y, k; y, u, v (colors)
* i, j, k matrices and such
* p, i, d; Kp, Ki, Kd in process control
* rv (return value), where it is clear what The Thing To Be returned is.
* common variables from eg physics
Generally because these are well known and defined in particular contexts.
I don't always make it, but sometimes an argument can be made that single letters are better known/recognizable by their single letter name.
Compare:
* total_energy = mass * light_speed_constant ^ 2
vs
* E=m*c^2
Or:
* process_control_setting = proportional_component + integral_component + derivative_component
vs
* q=p+i+d (for those of us who know PID control)
"Why don't you write out 'process_id'?"
"Because the people who maintain the sort of code that cares about pids all refer to it as 'pid'."
That's a nice compromise where you need to learn a few core concepts, but the code itself is easier to scan for bugs in a lot of places.
Python should be working on being the best Python it can be, not being an adequate Python and an inadequate bodged-on static language on the side.
Does the interpreter actually optimize code based on type information? My knowledge is that it does not
The problem Python 3 has is dynamic types, as the dynamically-typed languages implement them, are viral; one little crack lets them in somehow and all the code operating on the data has to assume it's viral.
[1]: https://mypyc.readthedocs.io/en/stable/
[2]: https://mypyc.readthedocs.io/en/stable/differences_from_pyth...
I'm hoping "Python 4" will be another language entirely that displaces it, Fixing some ecosystem problems upfront (packaging, concurrency/GIL). Nim is possible candidate, though Go is pretty popular w/ Pythonistas.
My personal unhappiness with how Py3K was handled, plus recent PSF events make me feel new leadership would also be a boon..
In fact, I'd been thinking about doing it since probably November of the previous year - and it's motivated by long-held beliefs that
Python's design falls short of the Zen;
several of the most common beginner pitfalls could and should be avoided by syntax changes and by a different approach to parsing the code; and
the standard library is full of ancient APIs that look terrible because they're motivated by C and Java designs that used to be the best we had but seem highly unidiomatic now.
It was somewhere in November or December last year that I first wrote those thoughts down more concretely (with details about what those pitfalls are etc.).
Given that pace of progress, however, I've more or less given up on ever expecting myself to publish something usable - by myself, at least. I've decided for now that it will be more practical to add blog posts about my ideas to the queue, and possibly see about my own implementation later.
If you're going to escape from Python, I think you need something more like Plissken.
I think the ecosystem leadership position Python finds itself in lately may well make Py-core silly enough to think "our users will tolerate our breaking-all-their-code antics no matter what". I suggest a more consenting-adults alternative here: https://news.ycombinator.com/item?id=41790766
Python3 did not break enough to justify the jump from 2 to 3, IMHO.
>>> and full support for explicit types will be one of the reasons.
Fair point!
I agree - it should have broken more (and thereby become able to fix more). It should also have been usable out of the gate and not majorly reworked (there was a serious battle over the syntax of byte and string literals, and possibly some other things, that resulted in 3.0 and 3.1 not seeing a full 5-year maintenance lifetime), and of course developers should have actually fixed stuff promptly and accepted that the obviously superior new ways of doing things were, in fact, obviously superior.
Unfortunately, a lot of other developers don't seem to agree.
And as for explicit types - I really wish people would stop trying to fight the type system - of Python, and of whatever other language. Python is not meant to support static types. It's not designed to reject your code at compile time for a type error and it isn't designed to take type information into account when generating bytecode. It's designed, instead, very explicitly, to let you care about what a given object can do, rather than about how it categorizes itself.
I don't know how much more breakage you really wanted out of Python 3 if "permanently scoured the public image of the language and caused many Python shops to, at least partially, stop being Python shops" wasn't enough.
(I say this as a still-fan of Python who has written quite a lot of it and contributed to MicroPython/CircuitPython's internals - I just also worked at a Python shop during the Py2->3 hell, and frankly, even my current dayjob still talks about that transition as a nightmare to watch out for if any other language starts doing similar talk.)
* Beginners don't introduce ACE exploits into their program from the get-go, because `input` is what `raw_input` was before and the "convenient" wrapper using `eval` was no longer available - so instructors were forced to teach students about explicit type conversions, like they should have been doing the whole time.
* You can't get `UnicodeDecodeError` from calling `.encode`, or `UnicodeEncodeError` from calling `.decode`, because you're never in the position of pretending that a sequence of bytes is a "string". There's no illogical "basestring" type and no `str` objects with ambiguous semantics - `.decode` and `.encode` do what they say, and belong to separate types. These problems resulted in a huge mess of duplicate Q&A on Stack Overflow full of incorrect advice from people with no clue what they were doing, and empowered people to ignore essential truths about Unicode until it blew up into a bigger problem.
* Similarly, when you read from a text file, you actually get text now.
* `print` used to be confusing and have weird ambiguities and tons of special syntax. Being a function means it can be taught the same way as any other function call; plus you get use as a higher-order function, unpacking operators (you can't do `print(*range(10))` in 2.x).
* `1000000000 in range(1000000000)` no longer hangs. `xrange` does not solve this problem (although it does improve matters quite a bit by avoiding high memory usage).
* Sorting heterogeneous lists correctly produces an error, rather than an ordering so strange as to merit its own Stack Overflow Q&A (https://stackoverflow.com/questions/3270680 and many duplicates). (You can still replicate the old order if you want.)
* `isinstance(x, int)` doesn't fail because of `x` being too large. This was a bizarre speed bump in such a high-level language.
* You can write '£' in your source code and you only have to declare an encoding if you use something other than UTF-8 (which Python correctly identified as the eventual winner).
When Python 3.2 came out I found it to be a breath of fresh air. By 3.4 I was already starting to wonder why so many others were dragging their feet on migrating.
History shows that's a good idea if and only if you use a new name for the new language.
cf Python 2 -> 3, Perl 5 -> 6 -> Raku, Javascript -> Typescript
You can keep Python as part of the name. Call it SuperPython or something. Just don't call it Python 4.
This is actually a good thing in some cases (possibly this one). Risky stuff should inherently be harder to do than safer stuff, otherwise people will reach for the risky alternatives when they don't need to, just to save time - or because they don't realize the risk.
Or at least, that's often the case. What's lacking here is evidence that this is actually happening. I can believe it, but evidence is necessary for breaking the language.
Python is not APL. Getting at the functionality in fewer characters is not a design goal - it's just a usually consequence of the actual design goal.
This is being considered because "Explicit is better than implicit." and because it helps avoid a common class of error (e.g. `except: continue` prevents aborting a loop with Ctrl-C, which is often not intentional).
Or as the PEP puts it:
> While this syntax can be convenient for a “catch all” handler, it often leads to poor coding practices: > > 1. It can mask important errors that should be propagated. > 2. It makes debugging more difficult by catching and potentially hiding unexpected exceptions. > 3. It goes against the Python principle of explicit over implicit.
Python isn't any other language, either. It certainly isn't taking design guidance from JavaScript (which runs in an environment where the page is expected to show something coherent, and not a loud screaming error, no matter how absurd the input data and/or code).
As for how much code it would break, you made me curious:
~/Desktop/dev$ find . -name "*.py" | wc -l
49433
~/Desktop/dev$ grep --include='*.py' -rnw . -e 'except.*:' | wc -l
109801
~/Desktop/dev$ grep --include='*.py' -rnw . -e 'except:' | wc -l
5692
~/Desktop/dev$ grep --include='*.py' -rnw . -e 'except[ \t]*:' | wc -l # just to make sure
5692
But drilling down further, over 2/3 of those bare excepts are in local copies of Python itself (i.e., multiple versions of the standard library) that I built from source. Probably all the rest are in dependencies. I don't write code like that myself if I'm even remotely paying attention. (Of course, that only tells me how many occurrences there were, not how many files have them. But the first two results imply an average of about 2 `except`s per file, so.)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.
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().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:`.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.
Your snippet has the opposite problem: if ex is a regular Exception, but then KeyboardInterrupt is raised by `log_tons_of_debug_info()`, then your snippet would mask that by re-raising ex in its place. I think the original snippet is probably better on balance, even ignoring difference in code complexity.
(there is also coredump but most distros disable or hide them, so it's not a problem in practice)
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.
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.
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.
For many users, in many cases, this would be fixing the code rather than breaking it.
Forcing people to write either `except BaseException:` or `except Exception:` means forcing them to think about which one they actually mean. This is a good thing, just like the enforcement of proper separation between bytes and text is a good thing.
There is a good chance it will fail to do that. See elsewhere in this thread.
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.
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.
2. Python does not use semantic versioning. 3.13 is a different major version to 3.12.
The anger from this potential change is that really all you are doing is taking something away that was working, and now people will need to review their code or keep python on a previous version which sucks.
I think that people who propose these kinds of changes don't appreciate the importance of the programming language being at the bottom of the stack so there's really never a good reason to break people even if you think it's nicer as you really can't appreciate how much work you are creating for people.
This is why I like to stick to C, Common Lisp, Clojure, and (to some extent) Java/JVM. I don't know about Clojure's future, but C and Common Lisp have been fine for the last 40 years, and I'm not expecting the least in the upcoming years.
What I don't like about say, c, is that it has various backward compatible additive dialects like c11 vs c99. I personally don't agree that c11 and c99 are the same language in spite of the backwards compatibility and I think it makes the entire ecosystem worse. At some point there needs to be a successor rather than just piling on to old broken designs. I would prefer a better FFI or other tools to interface with legacy code in the new dialect.
Also, I'm starting to get warning about something in tarfile that I will need to track down: https://peps.python.org/pep-0706/
Python 3.7.9 (default, Aug 23 2020, 00:57:53)
[Clang 10.0.1 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cgi
>>>
Python 3.13.0 (main, Oct 8 2024, 01:04:00) [Clang 18.1.8 ] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cgi
Traceback (most recent call last):
File "<python-input-0>", line 1, in <module>
import cgi
ModuleNotFoundError: No module named 'cgi'
>Hi everyone!
>Thanks a lot for voicing your opinions and concerns! After reading carefully all the arguments, the poll and the different positions we have decided that the best course of action is to withdraw the PEP as there is clear agreement that the breakage doesn’t justify the benefits here.
>Thanks a lot!
In particular, they'll commonly tell you to demonstrate your feature as a third-party package on PyPI first, then show that it gains popularity (i.e. you as a random developer are responsible for promoting your idea, not merely justifying it) - and if you succeed at that, they'll have the argument waiting for you that you already have a maintained, mature library that's perfectly capable of working on its own, so why would it need to become part of the language? "The standard library is where packages go to die", don't you know?
BTW, they will also tell you these things if the nature of your idea makes it impossible - e.g., you propose to add a method to a builtin type; subtyping won't work, because part of the point is that literal values should get the functionality automatically.
(These are the same people who humiliated Tim Peters and others.)
Oh, you want to know the naive UTC datetime in Python, to interface with something like PostgreSQL that recommends naive times? Back in the old days, a simple datetime.datetime.utcnow(). Now days, you need something like:
try:
from datetime import UTC as tz_UTC
except ImportError:
from pytz import UTC as tz_UTC
dt = datetime.datetime.now(tz_UTC).replace(tzinfo=None)
Postgres never recommended naive datetimes. A TZ-aware datetime is semantiacally the same as a tuple of (<location/agreed offset>, <time in the moment since unix epoch defined in terms of UTC>). Those who recommended dropping the knowledge of the first part from that pair did it because they didn't know better.
I think you're mixing rendering (and for that matter - time ordering) with the initial information providing, that is a precise data input that doesn't rely on anything external.
Postgres ALWAYS stores timestamps in UTC [1]. When you submit data for persistence from your application, you have a choice of either:
- informing the DB about the recorded location/offset at the point of persistence (even if it's the zero offset) so that the input conversion happens without any reliance on the underlying OS-level or configuration setting [2]
- or omitting that information and therefore 1) losing precision at the point of data input and 2) delegating the location/offset inference for the internal purpose of Postgres to the external global configuration: both side-effects are bad from consistency/reliability perspectives.
I've never seen a single application that would win anything from (2) compared to explicitly providing the offset of the observed moment, even if the entire business domain is in UTC at all times. In fact, I've seen many business applications that explicitly record the offset in a separate column next to the provided timestamps for any future analysis and retrieval. And it's partly by design of the underlying abstractions: the unix epoch is defined in terms of UTC too, so when you design your program around implicit UTC you are not gaining much - the offset information is still there, it's just your data types don't make it clearly visible to everyone. But the moment you start integrating your data with the real world that cares about global time ordering of your recorded data events, you get a whole bunch of silent mistakes and issues that you won't have enough data to fix reliably until you switch to explicit offsets in all timestamp evaluations.
[1] https://www.postgresql.org/docs/current/datatype-datetime.ht...
[2] https://www.postgresql.org/docs/current/runtime-config-clien...
Getting time zone conversions right all the way through the stack is far from trivial, which is why I prefer to do it in one place and keep the rest of the system out of it.
If Python 2 is acceptable for your use case, then you could stay on an old version of Python 3 just fine as well.
Don't forget the whole reason why Python 3 exists is because it broke compatibility with Python 2. Plenty of old unmaintained scripts were forever stuck in Python 2. Not to mention an old version of Python 3 actually performs worse than Python 2.
How about empowering people other than yourself to understand how the code works, rather than relying on them to decipher the precise way in which you "mixed bytes and strings copiously"?
What if someone else did it for you? Would you reject the PR on principle?
If the author, Adam, or someone else upgraded it I would be happy using it with Python 3. But the code works as is. I'm also happy using it with Python 2.
The way I was taught Python, you really, really don't want to use bare `except:`, because it catches _everything_: Ctrl-C interruptions, system exit, etc. Instead, you really ought to use `except Exception:` (where `Exception` is the base class for any "normal" runtime error).
So I definitely understand the rationale, but it's hard to say it's worth the pain of backward incompatibility - we have linters, style guides, etc. that can catch this.
All features of a language end up used, regardless of deprecation state.
In other languages, such a change would only be possible with a major version bump, though I imagine that because of the Python 3 collective trauma, the language designers now are OK with breaking older code without calling it Python 4. Anything goes, as long as it's called Python 3.
(Python lost me in the 2->3 migration and I haven't used it in a decade, so correct me if I'm wrong)
(Recent stdlib changes have been much more destructive, but I’m assuming that, like in the original thread, we’re drawing a distinction between those and changes to the actual language.)
Full disclosure, I welcomed Python 3, because for me that was the first time (since 2.4 on Windows XP) that I could count on my programs not randomly shitting their pants upon encountering Cyrillic in files or filenames, which for a native speaker of Russian you can imagine is quite important. (The csv stdlib module in Python 2 did that, IIRC. Perhaps I was holding it wrong, but experience shows that absolutely everybody did.)
We may never see a 4.0 because of the scar tissue, but the language continues to evolve.
They should do the opposite really. If it hurts, do it more often and get better at it. A perfect time would be when Python gets some nice JIT performance improvements which everyone will probably like.
Python: for the love of God [1] don't touch the version
I wonder if the scar tissue will ever heal and we'll see a Python 4 in two decades.
> This change is not backwards compatible. Existing code that uses bare `except:` clauses will need to be modified. To ease the transition:
> * A deprecation warning will be issued for bare `except` clauses in Python 3.14.
> * The syntax will be fully disallowed in Python 3.17.
> * A `from __future__ import strict_excepts` will be provided to invalidate bare except handlers in earlier versions of Python.
> A tool will be provided to automatically update code to replace bare `except:` with except BaseException:
Only proper response is private email from sane BDFL similar to Linus email of "WE DON'T BREAK USERSPACE"
EDIT: Add on, Private Email to Pablo going "Dude, why are you purposing stuff that will break code spectacularly? I think we need to talk about your approach to language design."
A bare except is something to be flagged up by tools, not disallowed by the language. It is definitely not worth a backward-incompatible change.
I am slowly going off Python.
This is not fixed in 24.2 btw, even if you do everything according to the latest standards - you're still allowed and expected to have a setup.py if you choose Setuptools as your backend and you release an sdist with a non-trivial build step. 24.3 should be out some time this month and I'll be interested to see if they've finally done something about this issue, which has existed for almost the entire lifetime of Pip.
Yes, the new version did mean I had to straighten out a few projects that were already working before, but they were working by coincidence because my code paths weren’t stumbling across the incompatibilities. The problem already existed. The new resolver just exposed it.
I'm fine with the those safety guardrails being the default behavior, but removing any sort of escape hatch because the pip devs think that they know better than the users of the tool 100% of the time is what I object to.
In the end we ended up ditching pip entirely for this use case and ended up with a much better system, with absolutely no disasters as a result, but we had a burn a lot of time and angst that could have been spent on actual problems we were trying to solve.
> If you don’t want pip to actually resolve dependencies, use the --no-deps option. This is useful when you have a set of package versions that work together in reality, even though their metadata says that they conflict. For guidance on a long-term fix, read Dealing with dependency conflicts.
Did that not work?
1. The language guarantees have become inconsistent, and the syntax breaks security boundaries or realtime guarantees that the language explicitly promises, and it is unfixable.
2. The universe of all written code is small enough that there are guarantees the syntax is unused, or we can change all instances of the syntax in an atomic manner.
Invalid reasons for backwards incompatible language changes:
1. Everything else.
Here's a C example.
C90 supported block comments with /* comment */.
C99 added BCPL style comments with // the rest of this line is a comment
They were already a common language extension and supported by C++.
Here's an example of C90 code that fails to compile under C99 because of // comments.
int x = 12;
int y = x //* I'm placing a comment here just to be difficult.*/ 3;
Should the committee have rejected this change to prevent breaking programs with similar code?The problem occurred when our scheduling program (Airflow) noticed the program was taking too long to run and decided to kill it. It sent a kill signal to Python, which dutifully caught the exception, retried and continued to run. I had to add a special case to allow Airflow to kill the program.
This PEP just forced me to look up the difference between the classes Exception and BaseException. It turns out that BaseException includes every exception, whereas Exception excludes those that are trying to exit the program (like SystemExit and KeyboardInterrupt).
In other words, your comment is an argument for the proposal!
I don't think it's a good enough argument to make a backwards incompatible change. This is a wart Python has to live with now. But I do think it's a shame that bare excepts behave in a way that is almost always a bug.
while True:
try:
serve()
except:
log(‘oops’)
so that it was more or less bulletproof. This might be a highly unpleasant change for those people who counted on it running 24/7 and never dying.In other words, the current behavior is a minor hassle for many people. That change would be a major hassle for a few.
I’d be all for a deprecation warning on bare excepts. That might nudge a lot of people to fix their code without actively breaking anything.
The PEP proposes a deprecation timeline for exactly this.
I’ll restate what I posted elsewhere, I have never come across anyone who actually wanted to write a bare except, only people who thought naively that it worked like “except Exception” actually does.
I understand people are grabbing pitchforks because everyone has at o e time or another written code using a bare except and they are thinking that this will break it, but they 100% intended that to work like “except exception” python could just make that the default for the bare exemption and keep the syntax.
Depreciating the behavior is a good choice, and anyone who actually wants to capture exit events or keyboard interrupt can explicitly capture those. If code breaks with this depreciation it’s because someone is doing something extremely out of the ordinary but isn’t being explicit about it.
First, consider this motivation from the PEP:
> Requiring specific exception types makes the programmer’s intentions clear and encourages thinking about what exceptions might occur.
This reeks of the same rationale for checked exceptions in Java. That was a failed experiment. You can't force people to deal with exceptions. They end up just swallowing them instead. It's better to propagate an exception than do that almost all the time.
Like will we see except: replaced with except object:? I don't even know if that's valid. It's never come up.
Second, this would be a breaking change. I really feel like this is where Python 3 went off the rails. In the Python 2 days making breaking changes was essentially verboten. But ever since Python 3 decided breaking changes were OK< it's like there's little restraint now and minor releases seems to be far too comfortable with this.
Going back more than a quarter century ago (!), I was one of those zealots in favor of checked exceptions in Java. It took a good 15 years to finally conclude the “checked” part is more trouble than it’s worth.
Given that there is inevitably a root context for any given language invocation (main() for a command li program, top of a thread for a multi threaded app, etc), unchecked exceptions and a top level handler have proven to be more than enough.
I won’t comment on Python backwards compat, will just shake my head.
> I figure if I make this PEP, we can then ask Guido to quickly reject it, and then when this argument next starts up again, we can say ‘Guido isn’t changing things to suit the tab-haters or the only-tabbers, so this conversation is a waste of time.’ ...
> This proposal, if accepted, will probably mean a heck of a lot of work for somebody. But since I don’t want it accepted, I don’t care.
I don't know if there are others.
Good as a reminder that rules like “explicit is better than implicit” should not be followed all the way to the most absurd possible conclusions.
They're using "evil twin" in the sense of "it's closely related to 758, but goes in the opposite direction to it".
So, if this thing is accepted, it pads the resume of certain people even more. And many software orgs will have one additional week of job security by rewriting existing code. It's a win-win situation.
Ever since the walrus operator coup Python has descended into madness and make-work initiatives.
You can just write code that is compatible with Python runtimes both before and after the change.
That means that you can use the same test suite, gradually getting the code more and more compatible with the new version, and you can switch your production runtime, without having to worry about a more complicated and involved rollback process.
Notably, in the Python 2->3 migration, it was not really possible (at first[*]) because "" (and b"") literals became -> b""
while u"" literals became -> ""
So, there was no way to write literals that would mean the same thing, and have the same type across the two versions
This is also the reason why libraries like six offered a `six.u` function (https://six.readthedocs.io/#binary-and-text-data) but that required banning use of non-ASCII codepoints in your string literals
[*] This was eventually addressed with PEP 414 (and of course, even with with PEP 414, the migration was not trivial)
This is all well and good for your own code, but it’s seldom the case the libraries. A new library release that ‘adds support for Python 3.14’ is very likely to include other changes in the same release that may or may not be trivial, even assuming you were already on the latest version of the library prior to needing to update. A change like this to the Python language might be trivial, but it would have a massive impact on the ecosystem.
There's no reason to believe that would be the case. The exceptions are:
- add support for Python 3.0 (that's of course a very different situation as I described before)
- eagerly adopt TONS of Python 3.14-only features (of course that means a different thing than "adds support for")
What a specific release claim to do is irrelevant. The library should run its test suite in CI against multiple Python versions.
in this specific case, updating to 3.14 just mean that the library stopped using bare excepts, which means that all version of Python pre-3.14 would still be able to use the library as usual (and thus, CI of those python versions can be retained).
If you're running a library with a version of Python against which it's not tested, of course you're in a precarious situation (and a bug that silently causes your code to behave differently is going to be a lot more tricky to deal with than a bit of syntax which is not supported anymore).
https://discuss.python.org/t/pep-760-no-more-bare-excepts/67...
I help maintain a small Python codebase at work (bulk of my work is in Verilog) and the number of times somebody's PEP science fair project has broken production code following a Python version upgrade is too damn high.
This is the sensible approach IMO to handle a hazardous programming construct. Warn people about it and give them the choice to shoot their foot.
But don't break their code.
From an outsiders perspective: The ecosystem is a disaster, on a level even exceeding that of JavaScript IMO. The 2->3 transition was awful and lead to a rift in the python community for years (still causes issues 15 years later). Maintainers seem happy to introduce breaking changes without major version bumps. It's not that performant of a language (slower than modern Ruby, for example). Best thing it's got going for it is readability.
I have literally used it instead of writing a curl one liner because I didn't feel like looking up the arguments.
Python is incredible for building tools, exactly like a small time machinist might build certain cutters for a part they are manufacturing, or a blacksmith build tools, or a welder building a jig, etc etc
I cannot fathom when people choose to build heavyweight or long lived applications and business products with it. Django is alright I guess, except that complicated database stuff will cause you problems eventually, and migrations are a lot of fuss for not as many guarantees as you would hope for the effort.
Developer productivity.
> Maintainers seem happy to introduce breaking changes without major version bumps
Nah. Keep in mind that this is a PEP, not an announcement of what is going to happen, see also https://peps.python.org/pep-0313/ .
I've never dealt with dependency issues with Python, but I've also not had to work with large projects with lots of dependences where conflicting transient dependencies became an issue.
> The 2->3 transition was awful and lead to a rift in the python community for years (still causes issues 15 years later)
At this point, this isn't really true. The 2->3 transition was a huge debacle, but at this point, it's water under the bridge. The only people still struggling are those that are stuck with a legacy code base written in 2.x.
> Maintainers seem happy to introduce breaking changes without major version bumps.
What's changed since 3.0 that's breaking, other than when async/await got added?
> It's not that performant of a language
I'll give you that. It's slow. But most would argue that if you're writing your core work and computations in Python, you're doing it wrong. Python is best treated as a glue between libraries written in a more performant language.
> Best thing it's got going for it is readability.
And there's the big reason for it.
Readability counts. It's huge. Code is read far more than it is written. Readability is why I consider Perl and Haskell as the antitheses of Python.
Basically, you choose Python when speed of development is more important than speed of execution.
I agree, though, that the ecosystem has many rough edges, especially when it comes to package management, dependency management, and environments/containers. This is especially true in the AI ecosystem, especially as a researcher, where I had to deal with third-party code that is sometimes written by people who are solid scientists but have little software engineering experience.
I'm now back in academia as a teaching-oriented professor; it's been a few months now since I've had to use pip and conda, though I have written some Python scripts to aid with grading. I teach C++ and Haskell to undergrads now, and I also have side projects involving Scheme and Common Lisp :).
ETA: Nobody is going to dig through a large codebase to find exactly what exceptions can be bubbled up if they didn't design it with explicit exception handling in mind from the beginning. It will also potentially become a pattern people will copy in new code.
I don't mind Python being improved, but as we learned from the 2->3 transition it should not be changed in ways that break old code. All that will do is have people forever sitting on an old version of Python. That's a worse situation that having code with bare excepts.
The fact that this pattern catches NameError and other things which are obviously design errors means that it is a really bad behavior which is unfortunately common.
Of course, many folks in this comment section and the PEP discussion thread point out the pitfalls with the suggested remedies. It would be great if some amount of linting/warning/static check could be devised to help people uncover the problem though.
To me, "if anything goes wrong, do the following" is perfectly valid semantics that appears a lot, and a bare excepts is a fine way to implement that.
I think what confuses these discussions is that a common "rookie mistake" is slapping on a bare except when you really should be specific.
For some people, this is reason enough to blindly enforce a "bare excepts" rule. To me, the costs vastly outweigh the benefits in this case.
At it's core, this might be a personality type issue more than anything else.
I still don't like the proposed change because of how much existing code it would break, but if we're designing a new language I approve.
I’m not much of a python programmer but my experience with the language would make me tend to agree actually. There are bigger fish to fry and so the effort to go after this relatively tiny sardine is perhaps not worth it.
The point of the pep is that it should be explicit, especially because the short form doesn't show whether catching terminating exceptions is a bug or intentional
Of course I'm catching broad exceptions because I have no idea what kind of exception is going to be thrown 12 dependencies deep and I don't want it to completely crash the program instead of letting me retry or do something else.
0:https://pylint.readthedocs.io/en/stable/user_guide/messages/...
With a Go project, I can leave it to sit for 3+ years and then pick it back up and add a feature without any issues. I've never had that with a Python project. (and this isn't even about the 2-to-3 situation, I just mean minor version to minor version and packages)
I don't really get preferring `except BaseException` over `except`. I'd love to get more info on possible exceptions though and I think it would cut down a lot of the catch all handling I see.
As far as I know, python doesn't give you any way of asking "what exceptions can this function run" - aside from just inspecting every line of code. I'd massively love to have those kind of details available.
I think for Python, rather than breaking bajillions of unpublished lines of code they should start with a more tentative & minimally invasive environment var/CLI switch opt-out warning that says something like "may be deprecated" where even the Python ./configure script lets you opt out at Python interpreter-compile-time. Measure the scope of the porting problem for a few years before trying to decide on The Plan for something that might be too disruptive.
[1] https://github.com/nim-lang/Nim/commit/91ce8c385d4ccbaab8048...
If you care about types, safety, etc. there are plenty of fantastic projects that share your priorities, but they don't need to bleed into everything under the sun.
Sharing and adopting new ideas is healthy, but homogenization kills creativity.
Maybe I'm just grumpy today.
try:
result = somethingrisky()
except SomeKnownException as e:
return handle_known_error(e)
except Exception as e:
log_error(e)
return None
return result
or something among those lines. And this is perfectly fine if that risky function e.g involves requests that in my experience can fail for a ton of reasons and it is hard to know them all.(Plus, the suggested transition easement, "A tool will be provided to automatically update code to replace bare except: with except BaseException:", indicates a fundamental flaw in this approach: it's still trivial for developers to catch-and-kill exceptions. So we're strictly increasing the verbosity of the language without actually solving the problem. :( ).
I used to think it’s likely that you can make a much stronger case for one side, but I personally feel that’s more for early language development phase. If it’s been a certain way for a long time, it ought to be overwhelmingly obvious and overwhelmingly supported by the community to change it. And even then I feel a bit of doubt.
But couldn’t the old code be automatically updated? E.g. wouldn’t replacing every ‘except:’ with ‘except BaseException:’ make old codebase compatible with the proposed change?
Sure, that’s a pain too and I’m not a fan of the change itself either; still, a breaking change that can be addressed automatically sounds relatively easy.
IMO the Python language is feature complete but the packaging system needs heart surgery.
Adding it was like making python dirty, like abolishing indentation in it.
Saving few keystrokes and sacrificing readability. Who even came out with such idea?
A compatibility nightmare of the same magnitude as Python 2 to Python 3 migration.
I'm sure it can, but some evidence of this actually happening feels rather critical for a change that will break the language for everybody.
https://discuss.python.org/t/pep-760-no-more-bare-excepts/67...
It still feels like `deno` is somewhat on the right track where permissions are dropped by default, but It'd Be Nice(tm) if programming languages enabled that a bit easier.
import sales_tax_calculator as xyz with [ cap.NETWORK, cap.FILESYSTEM, cap.USB, ...etc... ]
xyz.calculate( sales_price, state=user.address.state )
We're implicitly allowing imported libraries the full power of the containing programming language where with promiscuous code sharing (trending towards a low-trust environment), it'd be a lot better to _not_ give `cap.FS, NETWORK, USB, etc...` by default.Bringing it back around: `import somelib with [ cap.BARE_EXCEPT, cap.RAISE ]` or something to control their handling of "unknown" exceptions is interesting. Let them handle any exceptions or interrupts they've authored, but let me explicitly have control over catching stuff that isn't "from them".
...an extended version of dependency injection or inversion of control.
def loop():
try:
check_service()
except:
logging.exception("Error while checking service.")
time.sleep(60)
Really you shouldn't be using a base-except here. You should at the bare minimum catch `Exception`. Adding an implicit `raise` at the end will break this function without so much as a warning. Instead of calling the function every minute, the loop is broken with an unexpected exception that was deliberately suppressed (and logged).A more common scenario for myself is write a lot of my scripts in the style:
def main(argv: list[str]) -> int:
# Parse args, setup logging, etc.
try:
run_script(args)
except:
log.exception("Script failed.")
return 1
return 0
if __name__ == '__main__':
sys.exit(main(sys.argv))
An implicit raise would obnoxiously break them when my bare-except is intentional, and effectively cause the error to be printed twice to the terminal. Now I'm not wholly opposed to forcing `except BaseException:` instead of `except:`, but an implicit raise would cause all sorts of subtle bugs. except Exception:
resource.rollback()
raise
instead of except BaseException:
resource.rollback()
raise
and it's going to be really hard to insert a test case which ensures I really handled KeyboardInterrupt and the like.>>> try: ... raise TypeError ... except ValueError: ... print("keke") ... raise ...
TypeError will bubble up. If you want to catch everything, and handle it, like the example from Mailman[0], you should catch the base exception anyways.
This can be solved and detected by static analysis tools anyways.
[0]: https://gitlab.com/mailman/mailman/-/blob/master/src/mailman...
try:
risky_operation()
except:
handle_any_error()
with this: try:
risky_operation()
except Exception as e:
handle_expected_error(e)
and this will also be legal: try:
risky_operation()
except Exception as e:
pass
... seems fine to me, but its off the table anyway.And yet I have created my own habit of not using bare excepts. TIL what bare except even means, but I do not use them. Simply because I think it makes more sense to specify the exception I want to catch, and failing that I specify the base class Exception.
So I guess I understand the author of this PEP, we're of one mind on this. :)
Also thanks to this post TIL that a bare except might catch interrupts like ctrl-c. Even more justification for my new habit.
If this pep were implemented I suspect it would result in forcing thousands of not tens of thousands of people to spend hours modifying perfectly working code and destroying the ability to run old scientific code without modification. Extremely effective industrial sabotage if it were to be accepted.
It is hard for me to articulate how much peps like this reinforce my desire to never start another python project. Even if this pep is rejected the fact that there are people who would put in the time and effort to write and submit such a PEP tells me that they will do it again, and eventually they might succeed.
I completely understand this sentiment. Recent python events have made me wonder if there are some people intent on sabotaging the management of the language.
I loved the incremental improvements and thoughtful process involved up until a couple of years ago but it feels like python will become brittle and break badly if things continue the way they are. It feels like the adults have been driven out the room when it comes to stewardship. I'm not sure how recoverable the situation is.
- - - -
Oh! How could I forget!? The creeps actually banned Tim Peters!
I was, in a sense, in that camp at the time, before I looked it up. I felt that the operator went against the spirit of the language by trampling on what was previously a strong, and clearly very conscious, separation between statements and expressions. And I misguidedly imagined, and lamented, that GvR was unable to keep it out of the language, being overruled by consensus.
I just want to make sure it's clear that things are not like that. Rather, the Python envisioned (nowadays, though not originally) by the original leadership includes PEP 572 - and probably also the large majority of what's been added since.
It's not the "walrus operator" per se that's the problem, it's the change in project governance.
Python has been captured by bureaucracy and corporate interests. The way it's being improved-to-death is a symptom. The unceremonious eviction of Tim Peters indicates to me that the take-over is complete: the new guard feels comfortable throwing out the old guard, they expect that their power is such that no one will blink, and no one did. (No corporation withdrew support for them, the blow-back was all hot air.)
It would be interesting to know GvR's opinions of some of the new cruft, but it's not really relevant.
To be fair, the notion that pipes are lower-priority than other syntax needs is not exclusive to Python: in the JS world, discussion in https://github.com/tc39/proposal-pipeline-operator and specifically https://github.com/tc39/proposal-pipeline-operator/wiki/Bike... has been going on since 2018, with things like Tuple Literals taking precedence.
On the Python side, though, at least you can build your own pipes! You can define various helper classes that have, say, an `__rrshift__` method, to let you do the following with full type-checking support:
load_iterable_from_db() >> to_dict_by("id") >> tee(logger) >> call_(dict.values) >> to_dataframe
(With great apologies to FP folks who see a bind operator, and C++ folks who have seen enough operator overloading for a lifetime!)
Not necessarily something you want to use unless you want to confuse your team, but quite useful for fluent code in notebooks!
The 'pipe' is hacky, for example, because it's just syntactic sugar that only works in one specific case, and not in general.
The reason I pick up Python for projects is because it grows with the application; opportunities to add typing etc. Who knows maybe in a few years Python will enforce all the types and it will be as verbose as Java. Personally I’d like to see how they handle declaring a method or function throws exceptions.
Pretty narly we have compiled Python apps with poetry, it’s starting to punch out of its weight class.
If the change goes through, couldn't you just use older Python versions for those specific projects, or has the Python ecosystem still not figured out how to do this without huge hassles?
Python is open source. Nothing prohibits you from forking the 2.7 codebase and adding your own security patches (or more substantial things like back-porting new OpenSSL support, or even cherry-picking backwards-compatible features from 3.x that you do like), for example.
I'm happy when people criticize new features in Python. But I expect to read criticism of features based on their actual merits and consequences, not on the principle that it's new or backwards-incompatible or would cause "churn".
Then we have people saying "just don't upgrade anything if you don't want to deal with the churn" but that too is a very large burden for all the reasons I mentioned.
All the reasonable adults in the room want option 3: don't do the thing that causes needless churn.
> But I expect to read criticism of features based on their actual merits and consequences, not on the principle that it's new or backwards-incompatible or would cause "churn".
I am honestly shocked to see this attitude. Churn is a very real consequence. Do you have no respect for the time of the countless devs who use python?
It's bizarre to me that expecting people to improve their code incrementally is considered a disrespect for their time.
The proposed change is not arbitrary - which can be seen by trying to imagine the alternate universe in which the reverse change were proposed. One can imagine a world in which `except:` were added to a Python that didn't support it, but certainly not one where it were made mandatory (whether for the `except BaseException:` case or the `except Exception:` case).
I assume there are people out there who would, similarly, argue that it was "needless" to make `print` into a function (and thereby break users of the `>>file` syntax). But it demonstrably and significantly makes the language better.
Imagine whatever universe you want, but we live in this one. In this universe, there is a shitload of old python. Python 2.7 isn't even completely gone. Literal lifetimes of collective time would be spent on the fallout of this change, which does not seem worth the reward.
How could the people maintaining Python possibly avoid that? It would be up to Apple to proactively reach out to affected projects, if Apple cares about that.
TBH that kind of code barely survives minor Python version upgrades in my experience.
How do people land on the python steering council exactly?
> A tool will be provided to automatically update code to replace bare except: with except BaseException:.
I have sometimes not run a Python script for a few years, and then when I need it, it stopped working and I need to track down what changed/broke or run some tool or whatnot. I don't keep track of the latest greatest Python changes – like most Python programmers it's not my "day job" to write Python code so I now need to track what changed between "the Python version I used about 3 years ago, whatever that was" and now. It's pretty annoying.
And that's assuming said tool will be fool-proof. Never mind of course that all my dependencies (if any) will need updating too.
What will happen in practice is that people will write "except Exception:" rather than "except:" and do nothing different. Basically nothing will change.
Meanwhile, I have C and Go programs that have worked without modification for about 10 years. Not that nothing ever breaks in C or Go, but it's the exception (hah!) rather than the rule.
I’d love to know whether that’s true, and to what extreme. I believe you’re right - that people using Python for a few hours a week (or less) greatly outnumber software developers using it as their primary language.
I think that’s a real issue for the evolution of Python, because updates to the language design (e.g. the makeup of the Steering Council) come almost entirely from the second group.
Yes I agree, and it's disappointing to see some take such a narrow view of things.
A big part of maintaining and evolving a language is saying "no" a lot. There are a lot of people with ideas, almost always reasoned from their own use-case. That's okay, everyone does that to some degree, but there almost always trade-offs and such to consider.
Your job as Steering Council or Core Dev or BFDL or whatever governance you have is to consider all use cases and make a balanced decision. Reading that thread, some do. But unfortunately others don't.
Even for Python 3, Guido spent most of his time saying "no" to proposals. There were a lot of pretty wild ideas for Python 3000.
I propose a rider to the PEP in which implementation will be deferred until its proponents can correctly affirm that the library reference lists, for each function and method, every exception it might throw.
No, the goal is a system in which the code correctly indicates which exceptions it's intended to handle, and doesn't accidentally handle the wrong exceptions because the developer was either lazy or misinformed about the semantics (perhaps due to experience with a different programming language).
What support does Python offer, to the author of a function, for determining what would be the wrong exceptions for it to handle? How, in Python, does the author of a function signal, to the functions she is calling, which exceptions they should not handle? As I alluded to in my previous post, the Python language and documentation does not even give programmers a good accounting of what exceptions the library functions might throw.
I know it is not nearly on the same level, but people seriously overestimate the effort needed between not doing anything at all and even the slightest work, no matter how reliable and easy. The difference between nothing and anything is huge.
Like, I don’t know if there’s a PEP to use braces, but it wouldn’t surprise me if someone had made one so that from then on there’d be an official doc you could point people at when they ask about it.
Not saying this is one of those, and I see Brett Cannon’s on this one. I am saying not to get too worked up over the existence of a draft PEP.
The rejection of braces isn't in a PEP to my knowledge; it's only in the __future__ Easter egg.
sed -Ei 's/^([\t ]*except):/\1 BaseException:/' **/*.py
On the other hand, I completely agree that it's not worth a breaking change.
Even better/worse, could do it with regex on text streams.