← Back to list

I Didn’t Expect Python 3.15 to Change This Much

This Might Be the Biggest Upgrade in Years

Aysha R in Pythonic AF · 2026-05-21 05:30 · 801 claps · 6.5 min read paywalled
#python #python-programming #python315 #machine-learning #python3
Open on Medium ↗
Wiki topics: ML · Machine Learning EDU · Education & Learning 💻 · Programming

I Didn’t Expect Python 3.15 to Change This Much

This Might Be the Biggest Upgrade in Years

Every Python release claims to be faster, cleaner, smarter, more ergonomic, whatever.

Most of the time, the changes are either extremely niche or technically impressive but irrelevant to how people actually write Python.

Python 3.15 feels different.

Not because every feature is revolutionary. Some of them are honestly overdue. Some feel like cleanup work after previous experiments. And a few are the kind of thing only language nerds will care about.

Read the full story for free here on Medium

Canva

Canva

But this is one of the first Python releases in a while where multiple changes immediately affect normal development work.

Lazy imports alone will change how a lot of large Python applications start up.

And the funny thing is, Python 3.15 also includes a rollback of one of Python 3.14’s biggest changes.

Which honestly says a lot about Python development culture. They shipped the incremental garbage collector, people complained about memory usage, and now it’s gone again.

Good.

That’s healthier than pretending every experimental runtime change was secretly brilliant.

Lazy imports should have existed years ago

This is probably the most practical feature in the release.

Python startup time has always had this weird problem where importing half the ecosystem feels like paying taxes before your code even runs.

You import one framework. That framework imports six utility modules. Those import twenty more. Then your CLI tool takes two seconds to print --help.

People worked around this manually for years

if expensive_feature_enabled:
    import pandas

Or

def do_something():
    import torch

Not because the code looked good. Because startup latency mattered.

Now Python officially supports lazy imports.

Modules can be loaded only when actually used instead of during startup. And importantly, existing imports can often become lazy without rewriting the codebase into some cursed dependency maze.

That matters more than the syntax itself.

The real value here is for

  • CLI tools
  • developer tooling
  • large web applications
  • AI stacks with absurd import trees
  • basically every Python project that accidentally became an operating system

There’s also surprisingly little downside if your code already behaves properly.

Although let’s be honest: some projects are going to discover they relied on import side effects more than they thought.

Python developers love pretending imports are just declarations. A lot of imports are actually initialization scripts wearing fake glasses.

The JIT is finally becoming visible in benchmarks

Python introduced its JIT in 3.13.

The reaction was mostly

“Okay. Cool. Anyway.”

Because the speedups were small and inconsistent.

That wasn’t necessarily a failure. The first versions were clearly infrastructure work. But people hear “JIT compiler” and expect something dramatic.

Python 3.15 is the first version where the improvements start looking real.

The reported gains are around 8%–13% geometric mean improvements depending on workload and platform.

No, that does not suddenly turn Python into Rust.

But an automatic 10% speed increase in a language this widely used is not small either.

Especially because most Python performance work normally involves

  • rewriting hot paths in C
  • vectorizing everything into NumPy
  • adding caching layers everywhere
  • pretending asyncio solved architectural problems

If CPython can continue making ordinary Python faster without requiring ecosystem rewrites, that matters.

The interesting part is that the JIT improvements are not one single trick. It’s a collection of runtime optimizations

  • tracing improvements
  • better machine code generation
  • register allocation
  • reference counting optimizations

Basically the kind of low-level engineering most Python users never think about unless they accidentally open CPython internals.

Will developers notice immediately? Depends on the workload.

But unlike earlier versions, this no longer feels purely theoretical.

frozendict is one of those additions people argued about forever

Python almost never adds new built-in data structures.

So when it does, it usually means the ecosystem has already recreated the same thing badly a thousand times.

That’s basically the story of frozendict.

Immutable dictionaries already existed in libraries. People hacked around them with tuples. People wrapped dictionaries. People used custom classes.

Now there’s finally an official version.

config = frozendict({"host": "localhost", "port": 5432})

You can’t modify it. It’s hashable. It can safely be used as a dictionary key.

Simple.

Honestly this feels less like a flashy feature and more like Python finally admitting reality.

sentinel() fixes a surprisingly annoying pattern

This is one of those tiny features that sounds unimportant until you’ve written enough Python.

A lot of codebases do this

MISSING = object()

Why? Because None might be a legitimate value.

So developers create anonymous unique objects as placeholders.

The problem is those objects are ugly, not self documenting, awkward for type checking, and generally feel like a workaround.

Now there’s an official API

NOT_SET = sentinel("NOT_SET")

It’s clearer. It prints properly. It works better with typing.

This is exactly the kind of language improvement Python is usually good at.

Not revolutionary. Just reducing unnecessary weirdness.

The new profiler is probably more important than people realize

Python profiling has historically had a trade off

You either get precise profiling with major overhead, or lightweight monitoring with less detail.

cProfile tracked basically everything. Which also meant it slowed programs down heavily.

Now Python 3.15 adds a statistical sampling profiler.

That’s a much better fit for production ish performance analysis.

Instead of tracing every call, it periodically samples execution and estimates where time is spent.

Less precise. Far cheaper. Usually good enough.

Honestly, this is how profiling works in a lot of modern performance tooling already. Python was just oddly behind here.

And no, deterministic profilers are not going away. They still matter for certain debugging scenarios.

But for normal optimization work, sampling profilers are often the more realistic option.

Especially when developers already hesitate to profile because profiling itself changes runtime behavior.

Error messages continue getting less terrible

Python’s error messages have improved a lot over the past few releases.

This sounds minor until you compare modern Python errors with older versions that basically just shrugged at you.

Python 3.15 improves suggestions further.

One funny example

my_list.push(1)

Python now recognizes this is probably JavaScript brain damage and suggests

append()

That’s actually useful.

And honestly, modern programming involves enough language-switching that these mistakes are normal.

The attribute suggestions also got smarter in general.

Not groundbreaking. But better developer ergonomics accumulates over time.

People underestimate how much energy gets wasted on stupid debugging friction.

Unpacking inside comprehensions looks small but changes readability a lot

This feature will probably split people into two groups

  • “finally”
  • “this makes comprehensions unreadable”

Both reactions are fair.

Previously flattening nested iterables inside comprehensions looked like this:

[a for b in x for a in b]

Which is technically fine. But not exactly pleasant.

Now

[*a for a in x]

That’s easier to scan.

Dictionary unpacking also works

{**d for d in dicts}

The feature itself is straightforward.

The bigger issue is that Python comprehensions already have a habit of turning into competitive programming puzzles if people get too clever.

So this is probably one of those features that is great in moderation and terrible in the hands of developers who think one-liners are a personality trait.

The garbage collector rollback is actually a good sign

This might be the most interesting part of the release philosophically.

Python 3.14 introduced an incremental garbage collector intended to reduce pause times.

Reasonable goal.

Then users started reporting increased memory usage. Sometimes dramatically increased.

Python 3.15 rolls the change back.

And honestly, that’s fine.

A runtime optimization that causes memory bloat is not automatically worth keeping just because the implementation was complicated.

There’s a tendency in some ecosystems to defend every performance experiment forever because reversing course looks embarrassing.

Python backing out the change instead of pretending users imagined the problem is healthier.

The old generational garbage collector returns for now. The incremental collector may come back later after more work.

That’s probably the correct outcome.

Type system improvements keep expanding Python’s split personality

Python typing continues evolving into its own parallel universe.

Some developers love this. Some tolerate it. Some still treat type hints as decorative comments.

Python 3.15 adds more TypedDict controls like

  • closed
  • extra_items

Which make dictionary schemas stricter and more expressive.

There’s also TypeForm, which helps represent evaluated type expressions.

Useful? Yes.

Exciting? Depends how much time you spend fighting static analysis tools.

The reality is that Python now serves two very different audiences simultaneously

  • people who want flexible scripting
  • people building massive typed systems at scale

Sometimes the language handles that tension well. Sometimes it feels like two languages sharing syntax.

Canva

Canva

Python 3.15 feels unusually practical

That’s probably the main thing.

A lot of releases have impressive internal work that ordinary developers barely notice.

Python 3.15 includes several changes that directly affect

  • startup performance
  • profiling
  • runtime speed
  • error debugging
  • data modeling
  • code readability

Not every feature matters equally. Some are niche. Some will create arguments on Reddit for six months.

But this release feels grounded in actual developer behavior instead of language theory.

People complained about startup times. Python added lazy imports. People wanted immutable dictionaries. Python added one. People reported GC memory problems. Python reverted the change.

That feedback loop is probably the most reassuring thing here.

I still think some Python applications are becoming absurdly overengineered. The AI ecosystem especially seems determined to import the entire planet before printing a single token.

But at least CPython itself seems increasingly focused on practical pain points instead of pretending developer ergonomics and runtime behavior are separate topics.

We’ll see how much of this survives contact with real-world projects once 3.15 ships fully.

Some features will quietly become normal. Some will be abused immediately.

Some will probably disappear in future releases.

Which is also very Python.


메타데이터
post_id
bd4909d15e88
slug
i-didnt-expect-python-3-15-to-change-this-much-bd4909d15e88
url
https://medium.com/pythonic-af/i-didnt-expect-python-3-15-to-change-this-much-bd4909d15e88
canonical_url
https://medium.com/pythonic-af/i-didnt-expect-python-3-15-to-change-this-much-bd4909d15e88
author_url
https://medium.com/@tricky16122000
status
ok
fetched_at
2026-06-09 15:37:30