Here we go again. The tech sphere is buzzing, Medium articles are dropping, and the Python community is collectively celebrating the “revolutionary” features coming in Python 3.15.
I read through the latest feature announcements, and as someone who
has spent over four decades in IT, 3 of them writing Perl code, I
couldn’t help but smile. For years I have felt like Python is
essentially just Perl for folks who found Perl “too indecipherable”.
But Python it seems to me has become a Frankenstein monster born out
of someone’s irrational fear of curly braces and sigils (that’s @$%
for you Pythonistas).
And looking at the Python 3.15 changelog, it is clearer than ever: Python is not really innovating, it’s just improving itself by borrowing concepts that Perl has embraced like…forever.
Let’s take a look at the “groundbreaking” features in Python 3.15.
Python 3.15 introduces lazy import syntax to speed up initialization
times. The idea is simple: don’t load a heavy module until the exact
moment you actually need to execute it - because you might not need to.
Revolutionary, right? Except Perl developers have had require and
autouse for decades. Perl solved dynamic, on-demand loading back
when developers realized milliseconds (and size) matter when running web
applications. No special syntax proxy; Perl just trusts the
programmer to know when to pull things into memory (and complains
loudly if they forget).
Python is now touting the ability to use *group unpacking inside
list comprehensions so that developers can finally flatten nested
lists without writing confusing, double for-loop syntax.
Meanwhile, in Perl: @flat = (@list1, @{$list2}, %list3).
Lists just flatten. By default. Perl doesn’t make you go through hoops
(or loops) or wait for a major version bump to accomplish something as
mathematically fundamental as combining arrays. And for more exciting
ways of manipulating arrays see List::Util!
As much as I hate to see Perl bolt on too much syntactic sugar, some of the features of
List::Utilshould have been part of the language. The compromise was addingList::Utilto core in Perl 5.7.
Python 3.15 is finally adding frozendict as a built-in type to give
developers a truly immutable dictionary. I’m sorry, but frozendict?
Is that supposed to be some kind of locker room humor? I can’t wait
for Python 3.16 to introduce limpdict and of course the corrupted
hash - soredict.
Immutability is a good idea, especially for configurations. But
watching Python incrementally bolt on data-locking mechanisms rings a
bell. I think I’ve heard this one before. constant?, Readonly?,
Hash::Util::lock_keys? Buehler? Anyone?
When a developer accidentally tries to use JavaScript syntax in Python
(like .push() instead of .append()), Python 3.15 will now catch
the error and politely suggest the correct method. I think this says
something about the average Python developer by the way if they really
need this feature. I suppose (hope) it’s aimed at Python newbies. But
it is also a very polite, modern echo of Perl’s use diagnostics;
(which almost no Perl programmer today would leave in production code
and probably doesn’t even need while developing new code!).
Python is fine (I guess). It has clearly won the popularity contest in
the data science and ML spaces (and yes I’m jealous). These 3.15
updates - including a new Tachyon sampling profiler (see
Devel::NYTProf) and a much stronger JIT compiler - are genuinely good
improvements.
But let’s be honest, stripped of the marketing hype, Python is on a trajectory as predictable as Halley’s Comet. It morphed from a minimalist, heavily opinionated scripting language with OWTDI (one way to do it) into a language that is now appeasing developers looking for TIMTOWDI (there’s more than one way to do it)!
Python is begrudgingly bolting on the things I’ve always appreciated about Perl. It’s actually annoying to watch, especially since these are the exact same features Python developers originally claimed to hate about Perl.
| Feature | Python 3.15 | Perl 5.10 / Ecosystem |
|---|---|---|
| Lazy Loading / Delayed Imports | Introduces lazy import syntax to defer module loading. |
require and autouse |
| Flattening Nested Data | Allows *group unpacking directly inside list comprehensions. |
Native list context and array flattening (@flat = (@a, @b)) |
| Immutable Dictionaries | Adds frozendict as a built-in, read-only dictionary type. |
The constant pragma, Hash::Util::lock_keys, and the Readonly module |
| Helpful Error Messages | Provides contextual typo suggestions, like replacing .push() with .append(). |
The use diagnostics; core pragma |
| Zero-Overhead Profiling | Introduces the Tachyon Sampling Profiler for running processes. | The Devel::NYTProf CPAN module |
Python is finally catching up. Maybe in another 76 years, they’ll
discover the power of @_.