skip to navigation
skip to content

Planet Python

Last update: October 13, 2026 07:49 PM UTC

October 13, 2026


PyCoder’s Weekly

Issue #756: 3.15 Released For Real This Time, Muse, and More (2026-10-13)

#756 – OCTOBER 13, 2026
View in Browser »

The PyCoder’s Weekly Logo


The 5 Most Exciting New Features of Python 3.15

This article explains the 5 best new features of Python 3.15 with clear examples and explanations.
RODRIGO GIRÃO SERRÃO

How Fast Is Python 3.15?

Miguel benchmarks Python 3.15 RC3 and compares it to the performance of past releases as well as PyPy and even other languages.
MIGUEL GRINBERG

CodeAF: 2x OpenCode’s and 4x Claude Code’s solves, same model

alt

On DeepSWE, CodeAF solved 2× as many real GitHub issues as OpenCode and nearly 4× as many as Claude Code on the same open model, at up to 4.8× less per solved issue. A new open-source coding harness built for open models like DeepSeek, Qwen, GLM and Kimi, and it works with closed models too. Try CodeAF on GitHub
AGENTFIELD sponsor

What Is Meta Muse? A Plain-English Guide to Meta’s New AI

What is Meta Muse? Learn what Meta’s AI agent can do, what it costs, how it handles your data, and where Python fits in. No coding required.
REAL PYTHON

Python 3.15.0 Release Notes

PYTHON.ORG

PEP 755: Implicit Namespace Policy for PyPI (Withdrawn)

PYTHON.ORG

Django Security Releases Issued: 6.1.2, 6.0.9, and 5.2.18

DJANGO SOFTWARE FOUNDATION

Release of Polars 2.0

POLA.RS

Codex for Python Developers: Hands-On Agentic Coding Course

In this 2-day live course, you’ll build a complete Python CLI app from an empty directory with Codex CLI, an AI agent that reads your files, runs your tests, and fixes errors in your terminal. Sessions run November 7–8 on Zoom.
REAL PYTHON

Articles & Tutorials

P Is for Python Enhancement Proposal (PEP)

PEPs are proposals for how Python the programming language is changed. Even if you’ll never interact with them, reading them and the discussion around them will make you a better communicator.
JUHA-MATTI SANTALA

Codemoo: Demonstrating How Coding Agents Work

How do you assemble the core pieces of a coding agent? How are developers defining projects through conversation and introspection? This week on the show, Geir Arne Hjelle returns to talk about his recent project to demonstrate how coding agents work under the hood.
REAL PYTHON podcast

The Things You Own End Up Owning You

A recap of Pratham’s Quansight internship porting NumPy extension modules to the Limited API: heap types, swapping macros for function calls, and the side quest it started, getting NumPy ready for subinterpreters.
PRATHAM HOLE

Why Most Data Science Notebooks Die After Day One

Six habits that keep a notebook runnable after you close your laptop, including establishing imports and setup in your first cell, keeping to one function per cell, and more.
NATE ROSIDI

Generate Images in Python With OpenAI’s GPT Image API

Learn how to generate images from text prompts with OpenAI’s GPT Image API in Python, tune their size and quality, and edit them with a follow-up prompt.
REAL PYTHON

Quiz: Generate Images in Python With OpenAI’s GPT Image API

REAL PYTHON

Hugging Face Transformers: Leverage Open-Source AI in Python

Get hands-on with Hugging Face Transformers in Python. Download, run, and inspect pretrained open-source AI models, and speed up inference on GPUs.
REAL PYTHON

Saving Jet Fuel

This article shows you how to use the scikit-decide library to determine an optimal flight path to save jet fuel for a Boeing 787-9 Dreamliner.
MARK LITWINTSCHIK

Towards Async Transactions in Django

async with transaction.atomic() is coming to Django, hopefully for 6.2. This post talks about how we got there at Django on the Med, and what the rules will be.
CARLTON GIBSON

How We Built an Async-Aware Python Profiler

Learn how Datadog made Python profiling async-aware while reducing profiler overhead and preserving context across asyncio tasks.
KOWALSKI & GERRING

First Steps Into Memory Management in Python

A quick introduction to how Python manages memory under the hood and how that might effect your code.
DANIELL BASTOS

Show and Hide Wagtail Admin Fields Without JavaScript

Learn how to show and hide Wagtail admin fields easily without writing any JavaScript.
TIM KAMANIN

Projects & Code

django-prose-editor: ProseMirror-based HTML Editor

GITHUB.COM/FEINCMS

polynx: pandas-Style Query/Eval Strings for Polars

GITHUB.COM/LOWELLWINSTON • Shared by Lowell Winston

nvmon: A Fancy NVIDIA GPU Monitor for the Terminal

GITHUB.COM/HAN-DONGHEUN • Shared by Han DongHeun

pyEQL: An Interface for Water Chemistry

GITHUB.COM/KINGSBURYLAB • Shared by Michael Mulqueen

django-upgrade-report: Which Dependencies Block an Upgrade to Your Django Project?

GITHUB.COM/DERBLUB

Events

Weekly Real Python Office Hours Q&A (Virtual)

October 14, 2026
REALPYTHON.COM

PyCon NL 2026

October 15 to October 16, 2026
PYCON-NL.ORG

PyData Bristol Meetup

October 15, 2026
MEETUP.COM

PyLadies Dublin

October 15, 2026
PYLADIES.COM

Chattanooga Python User Group

October 16 to October 17, 2026
MEETUP.COM

PyCon Taiwan

October 17 to October 19, 2026
PYCON.ORG

PyCon Panamá 2026

October 22 to October 24, 2026
PYCON.PA

PyHo 2026

October 23 to October 25, 2026
PYTHONHO.COM

PyBeach 2026

October 24 to October 25, 2026
PYBEACH.ORG


Happy Pythoning!
This was PyCoder’s Weekly Issue #756.
View in Browser »

alt

[ Subscribe to 🐍 PyCoder’s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]

October 13, 2026 07:30 PM UTC


PyCharm

Two things are true about Python: It’s the most popular programming language in the world, and it’s the most common companion language for Go developers. How do we know that? From the Developer Ecosystem 2026 survey by JetBrains.

But we also know a lot more about the developers who use these two languages – both from quantitative data from different surveys, as well as qualitative data from our interviews with professionals who switched from Python to Go.

In this article, we share findings from these sources, going well beyond the simple syntax comparisons you will usually find. We will look at how the two languages differ, what the surveys tell us about the people who use them, and what our interviews say about the trade-offs between Python and Go, so that if you’re considering making the leap, you don’t have to dive in blind.

TL;DR

A note about the data

Unless stated otherwise, all survey figures come from the JetBrains Developer Ecosystem Survey 2026 (28,945 responses, fielded May–July 2026). We compare two groups: developers who selected Go among their primary languages (1,836) and developers who selected Python (11,298). The groups overlap, with 619 respondents selecting both languages. Therefore, every gap below is a conservative estimate of the real difference. Some questions were shown to only a part of each group, so bases are provided for reference. The qualitative material comes from interviews with developers who moved production workloads from Python to Go. We conducted the interviews between April and May 2026 and included seven participants who began using Go within the past year.

Python vs Go – languages compared

Core philosophy

On paper, Python and Go sound like they’d get along. Python lays out the core principles in the Zen of Python: Simple is better than complex, readability counts, there should be one obvious way to do it, etc. Go, as per Effective Go, “focuses on simplicity, reliability, and efficiency”, and is “specifically designed to make it easy to build software at scale”.

In practice, Python often optimizes for the person writing the code, offering multiple ways to say the same thing. Go optimizes for the person (or, nowadays, possibly the agent) reading someone else’s code two years later, so it picks one way to say most things and makes you spell it out. The goal is for all Go code to look like other Go code.

We point this out right at the beginning, because however similar these two philosophies look, this difference in approach underlies almost all the other language design differences that follow.

Ease of use and learning curve

Python is arguably one of the easiest programming languages to learn among those widely used in production. The syntax resembles natural language, the core set of constructs is small, and beginners can focus on programming ideas instead of language mechanics, leading to less frustration and faster results. Surveys consistently show Python to be one of the most popular programming languages (if not the most popular). In 2026, 10% of Python developers have been coding for less than a year, 23% are students or working students, and 19% hold junior positions, showing the language has a strong early-stage user base.

Python’s popularity among early learners is almost self-perpetuating. Initially, the language was well-suited to introductory courses and learning materials largely because it lets beginners print “Hello, world” with little ceremony, bypassing much boring theory in favor of real outputs. It also has the added benefit of being a generalist language that can handle a variety of use cases. Later, the sheer number of introductory courses and learning materials made it a natural choice for anyone who wanted to pick up programming but didn’t know where to start.

It’s not the same case with Go. In fact, you would be hard-pressed to find courses that teach you programming through Go. There are two reasons for that. First, Go 1.0 was released in 2012, long after Python had already become firmly embedded in CS curricula. The other is that Go solves problems that beginners don’t have. Explicit error handling, static types, and interfaces, which we’ll discuss later, all pay off across a large codebase maintained by a team over years. Go also has a much narrower set of implementations than Python, which makes it even less appealing for beginners.

That said, Go was also designed to be easy to learn, but for a different reason: Any large team should be able to onboard a new engineer quickly. Many Go developers will say that if you already know general programming concepts, you can become productive in Go in a matter of days or weeks. Developers we talked to said that Go “feels as easy to write as Python” and that it “strikes a good balance between Python’s simplicity and Java’s explicit nature”.

Syntax and readability

When you read Python, you can often follow it even without programming experience, because it reads relatively close to English. Python is dynamically typed, so type declarations are optional, though in practice, many companies and large codebases now write Python with type hints throughout, checked by tools like mypy or Pyright. Most of the ecosystem follows the formatting conventions set out in PEP 8, but they are still optional, and so some teams diverge from them.

Go, by contrast, is explicit and deliberately limited, which contributes to the cross-team readability we mentioned. It is statically typed, which makes it noticeably more verbose than Python. That was the main syntactic complaint raised by the developers we interviewed. Formatting in Go is not a matter of preference: gofmt will shape your code into the canonical form, whether you like the conventions or not.

One syntactic difference that developers consistently pointed out as a big adjustment when moving from Python to Go was error handling. Python lets you push failure handling to the edges of a function with try / except. Experienced Go developers clutch their pearls at the sight of that.

# Python: handle failure where it is convenient
try:
    profile = get_user(user_id)
except UserNotFound:
    return render_404()
// Go: handle failure where it happens
profile, err := getUser(userID)
if err != nil {
    if errors.Is(err, ErrUserNotFound) {
        return render404(w)
    }
    return fmt.Errorf("get user %s: %w", userID, err)
}

The Go version is longer, and in a large handler, developers will find themselves writing the if err != nil boilerplate ad nauseam. In return, they get control flow with no invisible jumps: Every path a value can take is explicit. Both approaches come with trade-offs.

Type system

Python’s dynamic typing checks types at runtime. This gives developers flexibility in writing and can speed up iteration, but it also means some type errors only show up when the code runs. The flexibility extends to the object model, which relies on duck typing: The code cares less about what an object is than what it can do. The developers we interviewed said they sorely missed duck typing, as it makes testing and mocking more difficult in Go.

Go checks types before the program runs. This results in fewer type-related failures reaching production and makes refactoring safer, but also causes code verbosity, as we touched on earlier.

Object model and polymorphism

Python is object-oriented in the way that most developers first learn the term. Everything is an object, and classes inherit from other classes (several at once, if you insist). Polymorphism works in two ways: down the class hierarchy when a subclass overrides its parent’s method, and sideways through duck typing, where anything with a read() method can be handed to code that expects a file.

Go has none of that hierarchy. There are no classes, no inheritance, and no way to declare that one type is a subtype of another. Instead, structs have methods attached to them, as well as interfaces that types satisfy implicitly without ever naming them.

# Python: the implementation announces its role
class Store(ABC):
    @abstractmethod
    def get(self, key: str) -> bytes: ...

class RedisStore(Store):
    def get(self, key: str) -> bytes:
        ...
// Go: the consumer declares what it needs; RedisStore never mentions Getter
type Getter interface {
    Get(key string) ([]byte, error)
}

func handleRead(g Getter, key string) ([]byte, error) {
    return g.Get(key)
}

Notice how the dependency runs. In Python, RedisStore inherits from Store, so the abstraction sits with the implementation. In Go, handleRead declares the one method it actually calls, and RedisStore never learns that Getter exists. That’s why Go developers say to “accept interfaces, return structs”, and that’s why interfaces stay small – io.Reader and io.Writer have a single method each.

Performance and speed

Go follows a traditional compilation model, producing a native binary. Python, on the other hand, takes a hybrid approach: Source code is compiled to bytecode, which the interpreter then executes.

As most compiled languages do, Go wins in terms of raw speed. You can compare the patterns across latency, throughput, and startup time on The Computer Language Benchmarks Game. Microbenchmarks like these don’t really translate directly to real workloads, and we wouldn’t be surprised if you made nothing of them. Our interviewees told us what the difference meant in production for them: One team migrated to Go after cold starts on AWS Lambda in Python exceeded 10 seconds; another measured a tenfold improvement in request times after rewriting their Python service in Go.

But raw language speed matters only when your service is actually compute-bound or latency-sensitive, and plenty of services are neither. Equally importantly, the Python interpreter is not slow where it counts most for one of its largest user bases. In machine learning, data work, and numerical computing, libraries like NumPy and PyTorch offload expensive operations to optimized native code, making interpreter overhead much less relevant. When we asked migrating developers where they decided to keep Python code, they confidently listed all AI and ML workflows – LLMs, chatbots, RAGs, and model training.

Memory management

Memory management is another important part of the performance discussion. Both languages manage memory for you, but differently: Go uses a tracing garbage collector, while CPython uses reference counting alongside a cyclic garbage collector. This affects what developers can fine-tune and what they need to design around.

Go’s GC runs concurrently with the program and is designed to minimize stop-the-world pauses. Developers can tune this behavior: GOGC and GOMEMLIMIT set the pacing, and the memory profile (heap and allocs) tells you when a service allocates too hard.

In CPython, an object is typically freed the moment its last reference disappears. Memory use is predictable, and pauses are rarely worth measuring, but the cost is spread across every operation, and there’s little to room tune it.   

Concurrency and parallelism

Even though both languages support concurrency, developers we talked to cited better concurrency as the reason why they switched from Python to Go.

Goroutines are central to Go’s design. They are lightweight threads managed by the runtime. They are cheap to create, carry little overhead, and scale to thousands of concurrent operations. The runtime handles the scheduling, which makes the model simpler than in Python – there is no separate async/await syntax, so a function is just a function. However, if you start to spawn goroutines without controlling their lifecycle, you’d better be ready to deal with race conditions, leaks, and deadlocks before long.

The other half of the concurrency model in Go are channels – typed conduits that pass values between goroutines and synchronize them. Instead of guarding shared state with a lock, Go can pass the value to whichever needs it next. A select statement waits on several channels at once, which is how Go expresses timeouts, cancellation, and fan-in using built-in language constructs. These very same primitives also produce common Go bugs: goroutine leaks and more deadlocks. 

Meanwhile, Python relies on standard libraries, single-threaded event loops, and sub-processes to work around interpreter constraints. It offers threading, but in CPython, the global interpreter lock (GIL) has historically prevented threads from running Python bytecode simultaneously, making it ineffective for CPU-bound parallelism. For I/O-bound concurrency, there is asyncio, and for real parallelism there is multiprocessing, but that adds memory overhead and requires inter-process communication.

It’s worth noting that the GIL itself is no longer a necessity – starting with Python 3.13, PEP 703 introduced an officially supported free-threaded build, and 3.14 continues that work. Most production code still runs with the GIL in place, but with each new release, the claim that “Python can’t do real threading” is becoming less true.

# Python: async/await, and the coloring that comes with it
async def fetch_all(urls):
    return await asyncio.gather(*(fetch(u) for u in urls))
// Go: ordinary functions run concurrently
var wg sync.WaitGroup
for _, u := range urls {
    wg.Add(1)
    go func() {
        defer wg.Done()
        fetch(u)
    }()
}
wg.Wait()

The approach to concurrency gives Go much of its practical advantage in high-throughput services, and having experienced both, our interviewees praised Go for being “async by default” and better suited for high-concurrency components, and they described it as having a superior concurrency model that’s highly performant and appealing for real-world use cases.

Libraries, frameworks, and IDEs

Go’s self-contained ecosystem

Go was never built as just a programming language, but as an ecosystem. As the Go team puts it, the goal was “an end-to-end platform with tooling all around the software development lifecycle” (Google for Developers), with formatters, test frameworks, dependency management, and security tools included in the toolchain, alongside a standard library that’s comprehensive enough to make external frameworks optional, if not irrelevant.

The Developer Ecosystem 2026 survey shows how successful the Go team has been in achieving that goal. For example, among Gophers, the standard html/template and text/template library packages are used by 31% and 22% of developers respectively, whereas the only other significant alternative – templ – is used by 11%.

Almost half of Gophers either don’t write unit tests or don’t use testing frameworks: 14% don’t write unit tests at all, and 35% don’t use frameworks for testing – the testing package provides everything they need in that regard. Others may also reach for tools such as Testify (31%) or GoMock (25%). The remaining libraries are far less popular.

For web development, 46% of developers use the standard net/http library, compared to 48% who use Gin. This proves that where a third-party framework exists, it doesn’t compete with the many other frameworks, but only with the standard library. Oftentimes, it loses.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go developers

Libraries and frameworks Go developers use

Template engines used for Go development

Which template engines do you use for Go development, if any?

None52%
html/template31%
text/template22%
templ11%
gomponents5%
pongo24%
Plush1%
Other2%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Go section (n = 1,529). Multiple answers allowed.

Testing frameworks and mock libraries in Go

Which testing frameworks or mock libraries do you regularly use, if any?

I write unit tests but don’t use any frameworks35%
Testify31%
GoMock25%
I don’t write unit tests for Go14%
Ginkgo7%
go-sqlmock6%
Godog5%
Gomega3%
GoConvey1%
Other2%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Go section (n = 1,518). Multiple answers allowed.

Go web frameworks in regular use

Which Go web frameworks do you regularly use, if any?

Gin48%
net/http46%
gorilla/mux15%
go-chi/chi15%
Echo13%
Fiber13%
None12%
Beego5%
Buffalo2%
Revel1%
Other5%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Go section (n = 1,519). Multiple answers allowed.

Python’s broad ecosystem

Python’s ecosystem works the other way around. The Python Package Index (PyPI) is vast and mature, and where the standard library stops, several strong alternatives tend to compete.

Take web frameworks, for example. Half of Python developers use FastAPI, and Django (31%) competes closely with Flask (30%). The data science landscape is more fragmented, and developers use those libraries simultaneously: 69% use NumPy, 68% use pandas, 50% use PyTorch, 49% use Matplotlib, etc. With Python, there’s often no clear leader, and choosing the right framework or library is part of the job.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Python developers

Frameworks and packages Python developers use

Web frameworks used with Python

What web frameworks / libraries do you use in addition to Python?

FastAPI50%
Django31%
Flask30%
None28%
Other3%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Python section (n = 4,276). Multiple answers allowed.

Data science packages used with Python

What data science packages do you use in Python?

NumPy69%
pandas68%
PyTorch49%
Matplotlib48%
scikit-learn35%
OpenCV32%
TensorFlow30%
SciPy29%
Seaborn20%
Keras15%
None14%
XGBoost13%
Polars8%
Other1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Python section (n = 4,277). Multiple answers allowed.

IDEs & editors

When it comes to editors, we see a similar pattern unfold. Go has an excellent language server, which makes general-purpose editors a viable alternative to a Go-specific IDE. When asked which IDEs or editors they use for Go development, 49% reported using GoLand, while 48% reported using VS Code. 

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go developers

IDEs and editors used for Go development

Which IDEs or editors do you use for Go development?

GoLand49%
Visual Studio Code48%
Zed14%
Cursor14%
Neovim10%
IntelliJ IDEA8%
Vim4%
Visual Studio4%
Sublime Text2%
Emacs1%
Windsurf1%
Atom<1%
Other4%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Go section (n = 1,529). Multiple answers allowed.

One reason is how much of Go’s surrounding ecosystem developers can access without having to assemble it themselves. GoLand installs with a test runner, debugger, coverage, and profilers wired into the toolchain. The analysis runs across the whole project, rather than only the open file. Interprocedural nil checks and unhandled-error inspections can catch the mistakes a Python developer might otherwise only see at runtime. Suffice it to say, Alan Donovan of the Go team has also described traditional IDEs like ours as setting “the gold standard” for refactoring because of their tight integration between the analysis logic and the user interface.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Python developers

Main IDE or editor for Python development

Which IDE or editor do you use the most for Python development?

Visual Studio Code41%
PyCharm22%
Cursor10%
PyCharm Pro8%
Jupyter Notebook5%
Vim / Neovim3%
IntelliJ IDEA3%
Zed2%
Notepad++2%
IDLE1%
Datalore<1%
Windsurf<1%
Emacs<1%
Other2%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who answered the Python section (n = 4,276). One answer per respondent.

The Python side is more fragmented and has more Python-specific options, such as Jupyter Notebook and, of course, PyCharm. The latter is used by 30% of Python developers (PyCharm – 22%, PyCharm Pro – 8%), with VS Code at 41%. Notebooks explain much of the fragmentation, since data and service work don’t necessarily require the same toolset. Whatever you build in Python, PyCharm has first-class support for your stack, your frameworks, and your workflow – for web, data, and ML workflows – with notebooks running alongside a debugger and type checker. It parses your code and resolves usages, types, and dependencies throughout your entire project. So you always know exactly what your code does and what will break if it changes, for you and your agents alike.

If you use both Go and Python – as a quarter of Gophers do – it’s worth noting that both GoLand and PyCharm are built on the same platform, so keymaps, shortcuts, and settings sync between them. GoLand also supports Python functionalities through the Python Community Edition plugin.

Python vs Go – broader landscapes

The language itself is one thing, but many other factors go into deciding which language you choose to work with. Developers consider what the languages are used for, who uses them, and how they’re maintained. In this section, we’ll provide insights on the factors that shape the broader landscapes of Python and Go.

Go developers are more senior

Across all questions about age, experience, and seniority in the Developer Ecosystem 2026 survey, Gophers tend to be further along in their career than Python developers.

On overall professional coding experience (not just experience in their main programming language), 20% of Go devs report 16 years or more, compared to 12% among Python developers. At the other end, 9% of Gophers have 1–2 years of experience, compared to 20% of Python developers.

Most Go professionals have senior roles, at 60%, with only 2% being trainees and 10% juniors. Meanwhile, 42% of Python professionals are seniors; trainees (6%) and juniors (19%) make up a quarter of the cohort.

72% of Go developers are employed full-time, compared to 51% of Python developers. Students and working students make up 8% of Gophers, compared to 23% of the Python population.

Finally, by age, the largest group of Go developers is aged 30–34 (23%), compared to Python’s largest group, aged 21–24 (22%).

These differences align with the point we made earlier: Python is a very popular first language for learners, while Go is almost never chosen as a first language and instead is picked up by more experienced developers later in their careers.

It’s important to keep this in mind as you read the following sections on developer demographics, because a lot of these numbers may look like differences between two languages, where in reality, they’re just differences between a senior population vs a general one that you would see regardless of what ecosystems you compare.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

Experience and seniority

Professional coding experience

How many years of professional coding experience do you have?

GoPython
Less than 1 year*Go 2%Python 10%
1–2 years*Go 9%Python 20%
3–5 yearsGo 22%Python 25%
6–10 years*Go 28%Python 19%
11–15 years*Go 17%Python 9%
16+ years*Go 20%Python 12%
No professional coding experience*Go 1%Python 5%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,298. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

Position level

What is the level of your current position?

GoPython
Trainee*Go 2%Python 6%
Junior*Go 10%Python 19%
Middle*Go 26%Python 30%
Senior*Go 60%Python 42%
OtherGo 2%Python 3%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,531, Python n = 6,891. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

Employment status

Which of the following best describes your employment and involvement in software development?

GoPython
Employed full-time*Go 72%Python 51%
Employed part-time*Go 2%Python 3%
Self-employed or freelancer*Go 10%Python 11%
Founder or business ownerGo 4%Python 3%
Working student*Go 4%Python 9%
Student*Go 4%Python 14%
Not employed, with development experienceGo 3%Python 3%
Learning as a hobby or career transition*Go 1%Python 4%
Other*Go <1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,298. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

Age

What is your age range?

GoPython
18–20*Go 4%Python 9%
21–24*Go 13%Python 22%
25–29Go 22%Python 21%
30–34*Go 23%Python 16%
35–39*Go 17%Python 12%
40–49*Go 18%Python 14%
50–59*Go 4%Python 5%
60 or older*Go <1%Python 2%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,298. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

Salary follows seniority

Salary bands clearly show how experience affects other demographic data. Go developers are better represented in the top bracket: 9% report earning more than $180,000 a year, compared to 6% of Python programmers. Meanwhile, Python users cluster more in the lowest brackets.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

Annual salary, USD

Salary bands in USD, converted from local currencies.

GoPython
Up to 1,000*Go 0%Python <1%
Up to 1,800Go 1%Python 1%
Up to 6,000*Go 4%Python 8%
Up to 12,000*Go 6%Python 8%
Up to 18,000Go 6%Python 6%
Up to 24,000Go 5%Python 7%
Up to 36,000Go 12%Python 14%
Up to 48,000Go 11%Python 10%
Up to 60,000Go 9%Python 8%
Up to 84,000Go 13%Python 12%
Up to 120,000*Go 17%Python 12%
Up to 180,000Go 8%Python 8%
More than 180,000*Go 9%Python 6%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,115, Python n = 5,004. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

However, if we look only at full-time developers, the differences are no longer statistically significant. The premium is attached to the seniority and employment status, not the primary language. In other words, learning Go itself will not guarantee you a higher salary, but the roles that require Go generally pay better.

What they build

The Developer Ecosystem survey also asks people what functionality their code implements.

Go developers more frequently reported:

Meanwhile, Python developers reported higher rates for:

The question of where their code is executed adds more context: A vast majority of Go developers target server, infrastructure, or cloud environments (74% compared to 57% of Python developers. On the other hand, 66% of Python developers target the desktop (Go – 47%).

Python is clearly a general-purpose language with a stronghold in AI, ML, and data work that favors local execution, while Go is heavily oriented towards networked services and infrastructure.

There is, however, a particularly interesting line item in the set: integration with AI. While AI development per se is a Python domain, integrations are not. 46% of Go developers report implementing AI integrations, against Python’s 44%, almost equal numbers. Asked about the types of development they do at work, 51% of Python developers reported working with AI and AI tools, compared to Go’s 48%. Go engineers may not train the models, but they are building AI-powered products at roughly the same rate as Python developers.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

What Go and Python developers build

What their code implements

Which specific functionality does your code implement?

GoPython
Integrating with APIs and services*Go 63%Python 47%
Providing APIs and services*Go 69%Python 41%
Integration with AIGo 46%Python 44%
User interface*Go 47%Python 41%
Application logic and workflows*Go 51%Python 37%
Data processing and analytics*Go 30%Python 38%
Libraries / frameworks*Go 35%Python 26%
Artificial intelligence and machine learning*Go 20%Python 36%
System tools and components*Go 27%Python 19%
Data science / data analytics*Go 15%Python 32%
Automating software testing and QA*Go 23%Python 20%
Ad hoc scripts*Go 18%Python 15%
Network communication protocols*Go 19%Python 12%
Security, encryption, and cryptographic protocols*Go 18%Python 13%
Audio or video processing*Go 8%Python 10%
Hardware interfacing and control systems*Go 8%Python 10%
Simulations and predictive modeling*Go 5%Python 9%
Rendering and processing graphics (2D/3D)*Go 5%Python 7%
Blockchain technologyGo 4%Python 3%
Other*Go <1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,298. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

Where their code runs

On which platforms is your code executed?

GoPython
Server / infrastructure / cloud*Go 74%Python 57%
Browser*Go 63%Python 57%
Desktop*Go 47%Python 66%
Mobile*Go 32%Python 26%
IoT / embeddedGo 11%Python 12%
WebAssembly*Go 7%Python 5%
Game consoles*Go <1%Python 2%
Other*Go <1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,298. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

Types of development at work

Which types of development are you involved in at work?

GoPython
Backend*Go 77%Python 54%
Full-stack*Go 55%Python 44%
AI and AI toolsGo 48%Python 51%
Infrastructure / DevOps*Go 45%Python 31%
Frontend*Go 39%Python 35%
Automated testGo 22%Python 20%
Data science and ML*Go 11%Python 27%
DesktopGo 18%Python 19%
MobileGo 18%Python 16%
Embedded and IoTGo 7%Python 9%
GamesGo 5%Python 4%
I don’t develop software professionally*Go 1%Python 6%
OtherGo 1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,595, Python n = 7,427. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

DevOps: Same job, different toolbox

One other point of convergence between Python and Go developers that deserves its own section is DevOps. Both groups are involved in that area, though Python developers (31%) somewhat less than Gophers (45%). The two groups also tend to use different tools.

So even if you move from Python to Go in the same type of role, the toolset change might be as big an adjustment as the language change itself.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

DevOps tools and practices

Container orchestration tools

Which container orchestration tools or services do you use?

GoPython
Docker ComposeGo 68%Python 65%
Kubernetes (incl. EKS, GKE, or AKS)*Go 58%Python 39%
Amazon ECSGo 14%Python 13%
I don’t use any such tools or services*Go 8%Python 17%
Docker SwarmGo 8%Python 7%
OpenShift*Go 2%Python 4%
HashiCorp NomadGo 2%Python 1%
Apache Mesos*Go <1%Python 2%
OtherGo 1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,435, Python n = 7,242. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

Configuration management and IaC tools

Which configuration management or IaC tools do you use?

GoPython
Terraform*Go 47%Python 37%
Cloud-native IaC tools (CloudFormation/CDK, ARM/Bicep, etc.)*Go 23%Python 29%
GitOps*Go 27%Python 21%
Custom scripts or in-house solutionsGo 22%Python 22%
AnsibleGo 21%Python 22%
I don’t use any such tools*Go 15%Python 21%
Puppet, Chef, SaltStack, or similarGo 4%Python 5%
PulumiGo 3%Python 3%
OtherGo 2%Python 2%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 930, Python n = 3,109. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

DevOps practices in use

Which of the following DevOps practices do you or your team currently use?

GoPython
CI/CD pipelines*Go 88%Python 83%
Containerization and orchestration*Go 61%Python 52%
Infrastructure as code (IaC)*Go 50%Python 42%
GitOps*Go 36%Python 26%
Platform engineering*Go 25%Python 18%
DevSecOpsGo 20%Python 20%
AI-driven operations*Go 12%Python 18%
Serverless (FaaS), multi-cloud, or hybrid cloudGo 17%Python 13%
We don’t use any DevOps practices*Go 2%Python 7%
OtherGo <1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 930, Python n = 3,110. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

Operating systems

A curious difference surfaced when we asked developers about the operating system they use for their development environment. Go developers work on macOS (70%) and Linux (57%) significantly more than on Windows (44%). Meanwhile, Python developers use Windows first (66%), then split almost evenly between macOS (54%) and Linux (52%).

For developers planning to migrate to Go, sticking with Windows doesn’t have to complicate deployment, even when the target is a Linux server. For pure Go, building a Linux binary from any of the three operating systems takes no more than two environment variables, while a Python deployment still has to find a matching interpreter and native packages, wherever it ends up.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

Operating systems for development environments

On which operating systems are your development environments?

GoPython
macOS*Go 70%Python 54%
Windows*Go 44%Python 66%
Linux*Go 57%Python 52%
OtherGo <1%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,298. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

Two different approaches to AI

We’ve already discussed using Python and Go for AI development, but what about using AI for Go and Python development? Both groups use AI heavily at work, but there’s a difference in how and what they use it for.

Go developers report using AI daily for tasks such as editing code across multiple files (60% vs 52%), agentic development of features or programs (51% vs 41%),  generating commit messages (51% vs 36%) and tests (47% vs 34%), or performing code reviews (39% vs 34%).

Meanwhile, Python developers lead on one task: learning new things about coding and software development (38% of Python developers vs 31% of Go developers), which is consistent with earlier data showing a larger early-career population among Python developers.

There is, however, a long list of tasks where the two groups are indistinguishable: refactoring, debugging, checking code for potential issues, asking general questions, or generating boilerplate – even though you’d expect Go developers to jump on the last one much more, considering the verbosity of the language.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

Tasks they use AI tools for every day

How often do you use AI tools for each of the following tasks at work? Share answering “Every day”.

GoPython
Generating code*Go 69%Python 64%
Editing code across multiple files*Go 60%Python 52%
Code completion*Go 55%Python 51%
Agentic development of features or programs*Go 51%Python 41%
Generating boilerplate, repetitive codeGo 45%Python 46%
Asking questions about software developmentGo 45%Python 45%
Generating code comments or documentation*Go 48%Python 42%
Generating commit messages*Go 51%Python 36%
Explaining bugs and offering fixesGo 40%Python 45%
Generating tests*Go 47%Python 34%
Improving or optimizing codeGo 40%Python 40%
Checking code for potential issuesGo 39%Python 41%
Performing code reviews*Go 39%Python 34%
Explaining codeGo 37%Python 36%
Brainstorming new ideasGo 35%Python 38%
Learning new things about coding*Go 31%Python 38%
Summarizing recent code changesGo 34%Python 34%
Debugging codeGo 32%Python 35%
Generating user documentationGo 32%Python 28%
Natural-language search for code fragmentsGo 31%Python 27%
Generating internal documentationGo 28%Python 24%
Refactoring codeGo 22%Python 22%
Converting code to other languagesGo 11%Python 13%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Respondents who rated these tasks (Go n = 993, Python n = 5,056); bases vary slightly by task. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

So AI-assisted coding is common in both ecosystems. Go developers have simply wired it into the production chores of a maintenance-heavy codebase: commits, tests, reviews, and multi-file edits.

The groups also tend to use different tools. Go developers are more likely to use terminal and agentic tools like Claude Code (45% vs 40%), OpenAI Codex (24% vs 17%), Cursor (17% vs 12%), and OpenCode (12% vs 6%). Python developers, in turn, reach more for general-purpose assistants and Google or Microsoft surfaces like ChatGPT (20% vs 16%), Google Antigravity (9% vs 5%), and Microsoft 365 Copilot (4% vs 1%).

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

AI tools used for coding at work

Which of these AI tools do you use for your coding and other development-related tasks at work?

GoPython
Claude Code*Go 45%Python 40%
OpenAI Codex*Go 24%Python 17%
GitHub CopilotGo 18%Python 19%
ChatGPT (web, desktop, or mobile app)*Go 16%Python 20%
Claude (web, desktop, or mobile app)Go 16%Python 17%
Cursor*Go 17%Python 12%
OpenCode*Go 12%Python 6%
Google Antigravity*Go 5%Python 9%
Google Gemini (web or mobile app)Go 6%Python 7%
JetBrains AI Assistant*Go 7%Python 5%
DeepSeek (apps or self-hosted)Go 5%Python 4%
CodeGPT plugin in VS CodeGo 5%Python 3%
Zed*Go 5%Python 2%
Gemini CLI*Go 2%Python 4%
JetBrains Junie*Go 4%Python 2%
Microsoft 365 Copilot*Go 1%Python 4%
TraeGo 2%Python 2%
Gemini Code AssistGo 1%Python 2%
CodeRabbit*Go 2%Python 1%
Google AI Studio*Go <1%Python 2%
PerplexityGo 1%Python 2%
TONGYI LingmaGo 2%Python 1%
WindsurfGo 1%Python 1%
Qwen CodeGo 1%Python 2%
Amazon Q DeveloperGo 1%Python 1%
OpenClaw*Go 1%Python 1%
JetBrains AirGo 1%Python <1%
DevinGo 1%Python 1%
Gemini in Android Studio*Go <1%Python 1%
Warp / OzGo <1%Python 1%
Cline*Go <1%Python 1%
NoneGo <1%Python 1%
ConductorGo 1%Python <1%
AmpGo <1%Python <1%
FactoryGo <1%Python <1%
BLACKBOX AI*Go <1%Python <1%
Google JulesGo <1%Python <1%
GitHub Agent HQGo <1%Python <1%
TabnineGo <1%Python <1%
GitLab Duo Agent PlatformGo <1%Python <1%
SupersetGo <1%Python <1%
GraphiteGo <1%Python <1%
Ona (previously Gitpod)Go 0%Python <1%
OtherGo 2%Python 1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,482, Python n = 6,747. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. * Statistically significant difference (p < 0.05, adjusted).

One number that has to change

Software development remains a heavily male-dominated field, and the gap is particularly pronounced in Go, which – as it’s typically people’s second language – inherits whatever the pipeline hands it and exacerbates it further. In our sample, only 1.8% of Go developers identify as female, compared to 5.8% of Python developers.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

Gender

What is your gender?

GoPython
Male*Go 95.8%Python 90.8%
Female*Go 1.8%Python 5.8%
Non-binary, genderqueer, or gender non-conforming*Go 0.6%Python 1.2%
Prefer not to sayGo 1.8%Python 2.2%
Other*Go 0%Python 0.1%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,833, Python n = 11,284. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. * Statistically significant difference (p < 0.05, adjusted).

Transitioning from Python to Go

One-way path well traveled

You may ask why we’re focusing on transitioning from Python to Go, not the other way around. The data leaves little doubt about the path developers are taking. Python is already the most common second language among Go developers – 35% of Gophers declare it as their other primary language. But most Go developers (70%) say they have no intention of adopting another language in the next 12 months, and if they do, they name Rust (16%), rather than Python (2%). On the other hand, 10% of Python developers (a much larger cohort in terms of absolute numbers) plan to pick up Go, roughly 5.5 times the rate at which Go developers plan to pick up Python.

.jb-pvg{--jb-pvg-go:#007d9c;--jb-pvg-py:#6b57ff;--jb-pvg-t:#19191c;--jb-pvg-mu:#6b6b73;--jb-pvg-li:#d9d9e3;color:var(--jb-pvg-t);font:inherit;margin:32px 0}.jb-pvg *{box-sizing:border-box}.jb-pvg-panel{background:#fff;border:1px solid var(--jb-pvg-li);border-radius:8px;padding:24px}.jb-pvg .jb-pvg-eyebrow{color:var(--jb-pvg-mu);font-size:12px;font-weight:700;letter-spacing:.08em;line-height:1.4;margin:0 0 6px;text-transform:uppercase}.jb-pvg .jb-pvg-title{color:var(--jb-pvg-t);font-size:20px;font-weight:700;line-height:1.3;margin:0}.jb-pvg .jb-pvg-q{color:var(--jb-pvg-mu);font-size:14px;line-height:1.5;margin:6px 0 0}.jb-pvg-legend{display:flex;flex-wrap:wrap;gap:6px 18px;margin:16px 0 0;color:var(--jb-pvg-mu);font-size:13px;line-height:1.4}.jb-pvg-key{display:inline-flex;align-items:center;gap:6px}.jb-pvg-key:before{content:"";display:inline-block;width:12px;height:12px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-key-py:before{background:var(--jb-pvg-py)}.jb-pvg-rows{margin:12px 0 0;padding:0}.jb-pvg-r{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);gap:4px 16px;align-items:center;padding:7px 0;border-top:1px solid #ececf2}.jb-pvg-r:first-child{border-top:0}.jb-pvg-l{min-width:0;font-size:14px;line-height:1.35;overflow-wrap:anywhere}.jb-pvg-m .jb-pvg-l{color:var(--jb-pvg-mu)}.jb-pvg-s{color:var(--jb-pvg-mu);margin-left:2px}.jb-pvg-bs{display:grid;gap:3px;min-width:0}.jb-pvg-ln{display:flex;align-items:center;gap:8px;min-width:0}.jb-pvg-b{display:block;flex:none;width:calc((100% - 56px) * var(--w));height:10px;min-width:2px;border-radius:2px;background:var(--jb-pvg-go)}.jb-pvg-bp{background:var(--jb-pvg-py)}.jb-pvg-z{min-width:0}.jb-pvg-m .jb-pvg-b{opacity:.5}.jb-pvg-v{flex:none;min-width:44px;font-size:13px;line-height:1.2;font-variant-numeric:tabular-nums;white-space:nowrap}.jb-pvg-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.jb-pvg-collapsed .jb-pvg-x{display:none}.jb-pvg .jb-pvg-toggle{display:inline-block;margin:12px 0 0;padding:6px 12px;background:#fff;border:1px solid var(--jb-pvg-li);border-radius:6px;color:var(--jb-pvg-t);font:inherit;font-size:13px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-toggle[hidden]{display:none}.jb-pvg .jb-pvg-toggle:hover{border-color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-toggle:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:2px}.jb-pvg .jb-pvg-note{color:var(--jb-pvg-mu);font-size:12.5px;line-height:1.5;margin:14px 0 0}@media (max-width:560px){.jb-pvg-panel{padding:18px}.jb-pvg-r{grid-template-columns:minmax(0,1fr)}.jb-pvg .jb-pvg-title{font-size:18px}}.jb-pvg .jb-pvg-tabs{display:flex;flex-wrap:wrap;gap:2px 4px;margin:16px 0 0;padding:0;border-bottom:1px solid var(--jb-pvg-li)}.jb-pvg .jb-pvg-tabs[hidden]{display:none}.jb-pvg .jb-pvg-tab{margin:0 0 -1px;padding:8px 12px;background:none;border:0;border-bottom:2px solid transparent;border-radius:0;color:var(--jb-pvg-mu);font:inherit;font-size:14px;line-height:1.4;cursor:pointer}.jb-pvg .jb-pvg-tab:hover{color:var(--jb-pvg-t)}.jb-pvg .jb-pvg-tab[aria-selected="true"]{color:var(--jb-pvg-t);border-bottom-color:var(--jb-pvg-t);font-weight:700}.jb-pvg .jb-pvg-tab:focus-visible{outline:2px solid var(--jb-pvg-py);outline-offset:-2px}.jb-pvg-card+.jb-pvg-card{margin-top:24px;padding-top:8px;border-top:1px solid var(--jb-pvg-li)}.jb-pvg-tabbed .jb-pvg-card+.jb-pvg-card{margin-top:0;padding-top:0;border-top:0}.jb-pvg-card[hidden]{display:none}.jb-pvg .jb-pvg-ctitle{color:var(--jb-pvg-t);font-size:16px;font-weight:700;line-height:1.35;margin:16px 0 0}@media (max-width:560px){.jb-pvg .jb-pvg-tab{padding:8px 10px;font-size:13px}}

Go vs Python developers

Languages they plan to adopt in the next 12 months

Do you plan to adopt or migrate to other languages in the next 12 months? If so, which ones?

GoPython
Not planning to adopt any other language*Go 70%Python 61%
Rust*Go 16%Python 13%
Go*Go n/aPython 9%
C++*Go 3%Python 5%
Java*Go 2%Python 4%
Swift*Go 2%Python 4%
TypeScript*Go 2%Python 4%
Kotlin*Go 2%Python 4%
C#*Go 2%Python 3%
JavaScript*Go 1%Python 3%
CGo 2%Python 2%
SQL*Go 1%Python 3%
Python*Go 2%Python n/a
RubyGo 1%Python 2%
Shell scripting languages*Go 1%Python 2%
PHPGo 1%Python 1%
ElixirGo 2%Python 1%
DartGo 1%Python 1%
R*Go <1%Python 2%
HTML / CSS*Go <1%Python 2%
LuaGo 1%Python 1%
Assembly*Go <1%Python 1%
ScalaGo 1%Python 1%
MATLAB*Go <1%Python 1%
HaskellGo 1%Python <1%
Julia*Go <1%Python 1%
Visual Basic*Go <1%Python 1%
Platform-specific language (Apex, ABAP, 1C, etc.)*Go <1%Python 1%
PerlGo <1%Python <1%
COBOL*Go <1%Python <1%
GroovyGo <1%Python <1%
Objective-C*Go 0%Python <1%
LabVIEW*Go <1%Python <1%
F#Go <1%Python <1%
Delphi*Go 0%Python <1%
Clojure / ClojureScript*Go <1%Python <1%
CoffeeScript*Go 0%Python <1%
AdaGo <1%Python <1%
OtherGo 3%Python 2%

Source: JetBrains Developer Ecosystem Survey 2026, weighted data. Base: Go n = 1,836, Python n = 11,295. Go and Python developers are respondents who selected the language among their primary languages; those who selected both are counted in both groups. Multiple answers allowed. n/a: respondents already use this language as a primary one. * Statistically significant difference (p < 0.05, adjusted).

Why make the switch from Python to Go?

Despite working in different roles and on different products, the developers we interviewed gave consistent reasons for transitioning from Python to Go. These were:

What they gained and what they lost

Perceived potential gains are one thing, but did Go actually deliver? According to the developers we interviewed, it did in the areas described above. But they also found benefits they weren’t expecting: predictable formatting and linting that contributed to “clean code”, out-of-the-box tooling, and simplicity comparable to Python’s.

But Go also has flaws that are obvious to developers coming from Python. Just like the reasons for adopting Go were consistent, so were the complaints:

Did they really leave?

“Migrating”, “transitioning”, and “switching over” may all sound like final decisions to leave Python behind, but that’s not really the case. Not one of the developers we interviewed removed Python from their stack completely. They kept it for artificial intelligence and machine learning, data science, and pipelines on platforms that only support Python, as well as simply because they work on larger teams that already know Python and are productive in it.

The realistic outcome of “moving to Go” is not becoming a monoglot, but having a polyglot codebase where each language is used for what it’s best suited for.

Conclusions

So, which language should you choose? Is it worth dropping Python in favor of Go? We hope that by now the answer is clear – it’s not a matter of which language is better, but which one is a better fit. Based on our data and developer testimony, here’s what we found.

Go may be a better fit if:

Python may be a better fit if:

Language features alone rarely determine the best choice. When deciding what to build with, the teams weigh in the toolchain they already run, the languages their colleagues already know or are willing to learn, and how much of the existing system they are willing to change. Those things carry more weight than any benchmark, and they are why developers we talked to ended up using both languages, instead of choosing one.

Frequently asked questions

Can Go replace Python completely?

For a lot of backend work, yes, in principle. In practice, it doesn’t. None of the developers we interviewed removed Python from their stack completely. They kept it for machine learning and data science, for pipelines on platforms that only accept Python, and because the teams around them already know it. In the Developer Ecosystem 2026 survey, about a quarter of Go developers report using Python in the same project.

Is Go good for data engineering?

It depends on which end of the pipeline you mean. Go works well for moving data around, including ingestion services, stream processing, API integrations, and CLI tooling, and 30% of Go developers report working on data processing and analytics, compared with Python’s 38%. The analytical end is a different story: Only 15% of Gophers do data science and data analytics, against 32% of Python developers, and the library ecosystem reflects that.

How long does it take a Python developer to learn Go?

Days to weeks for the language itself. The syntax is small, gofmt settles the formatting arguments, and developers we talked to said Go “feels as easy to write as Python”. What takes longer is everything around it: system concepts such as pointers, interfaces, goroutines, and channels, as well as the habits Go asks you to change, from explicit error handling to designing test seams instead of patching at runtime.

The bigger adjustment may not be the language after all. Go work tends to sit closer to Kubernetes, Terraform, and GitOps, so if you’re moving into a Go team from a Python one, budget as much time for learning the toolchain as for the syntax.

Is Go good for machine learning?

For training models, probably not. 20% of Go developers work on artificial intelligence and machine learning, against 36% of Python developers, and the developers we interviewed were blunt about why: Python has the libraries, while Go lacks equivalents.

When it comes to building products around the models, it’s a different story. 46% of Go developers implement AI integrations, against Python’s 44% – a negligible difference. Gophers generally aren’t training the models, but they sure are serving them.

Can Go and Python be used in the same project?

Not only can they be used together, they often are. 27% of Go developers report using Python alongside Go in the same project, behind TypeScript (43%) and just ahead of JavaScript (24%). We know from interviews that the usual division of labor follows each language’s strengths: Go for the networked services and infrastructure, Python for data work, machine learning, and anything that depends on the scientific library stack.

October 13, 2026 01:41 PM UTC


Rodrigo Girão Serrão

Sentinel built-in

Learn how to use the sentinel built-in from Python 3.15 for placeholder values.

Python 3.15 introduced the new sentinel built-in. The sentinel built-in can be used to create placeholder values:

NOTHING = sentinel("NOTHING")

A placeholder created by sentinel is the more idiomatic way to provide default arguments or return values where None wouldn't be usable.

15 days of Python 3.15

To celebrate the release of Python 3.15, over the next 15 business days I'll be writing about a new 3.15 feature every day. Explained clearly and with examples so you don't have to sift through the changelog.

Subscribe to receive this free email series:

If you want, you can also check the schedule of the upcoming emails.

Creating and using sentinels

The built-in sentinel accepts a string argument which is the name of the sentinel:

NOTHING = sentinel("NOTHING")
print(NOTHING)  # NOTHING

The name of the sentinel is used as its default string representation.

Alternatively, you can provide a second named argument to be used as the representation of the sentinel:

NOTHING = sentinel("NOTHING", repr="__main__.NOTHING")
print(NOTHING)  # __main__.NOTHING

While there's no runtime restriction imposed, the name of the sentinel and the name of the variable that the sentinel is assigned to should match:

# Correct:
NOTHING = sentinel("NOTHING")

# Wrong:
NOTHING = sentinel("nothing")
N = sentinel("NOTHING")
BANANAS = sentinel("APPLES")

Linters and type checkers may complain if there's a mismatch. Since sentinels are typically constants you won't update, it's also common for sentinels to have names in all uppercase.

Sentinels are typically used as placeholders and the most common operation is to check if a value is a specific sentinel. For example, imagine a function find that looks...

October 13, 2026 01:11 PM UTC


PyCharm

Python vs Go: A Practical Comparison for Developers

October 13, 2026 09:02 AM UTC


Seth Michael Larson

Gaming’s all-digital future doesn’t include “Sonic the Hedgehog 3” and “Pikmin 2”

Sony announced that all games from 2028 and onwards would be digital-only. It seems likely that Xbox will follow and that Nintendo will continue making “physical” releases for first-party games during the Switch 2 generation.

In the all-digital gaming future, every game platform will be subject to the same problems and constraints as media streaming services like Netflix and Spotify. We can see hints of how this will affect future games and creative freedom in the medium by looking at re-releases of older games, in particular: Sonic the Hedgehog 3 and Pikmin 2.


The core problem is that digital games are licenses, which forces an ongoing relationship between you and the owner of the media. And because there’s an ongoing relationship with you, any ongoing licensing relationships that the media owner has also affect you and your games. If a license for any media that is part of the game expires or is affected, then the developer must take action to remediate the “issue” in the game.

This is already commonplace for games that feature music, such as Rock Band or Guitar Hero, but maybe players find this more “expected” because these games are essentially a music streaming service in themselves. But what about games that aren’t like this on the surface?


Sonic the Hedgehog 3 for Genesis (1994), GameCube (2002), and Switch (2022)

Sonic the Hedgehog 3 was originally published in 1994, and beyond the game being great to play, the soundtrack is really something special. I have fond memories of dancing to the end credits music on my parents’ bed with my brother as a kid after beating the game.

Unfortunately, this track and many others in the game would not survive our all-digital future. Michael Jackson’s alleged uncredited involvement with Sonic 3 has meant that all re-releases of Sonic 3 since 2009 have not included the entire original soundtrack. If this game were released only digitally today, it can be assumed that these tracks would be pulled from the game, just as is done for Rock Band and Guitar Hero when licensing terms expire or there are legal issues.


Pikmin 2 for GameCube (JP, NA, PAL, 2004) and Switch (2023)

Pikmin 2 was published in 2004, and the main objective is collecting “treasure” from an alien planet in the form of food, toys, and, most surprisingly, items featuring real-life brands like Duracell, Dr. Pepper, Yoo-Hoo, and Snapple. This artistic decision and the work to license and include these brands were a substantial part of the surprise and delight while playing the game.

However, you can see that these licensing terms eventually run out, too: in all re-releases of Pikmin 2 from 2023 onwards, the real-life brands are replaced with generic fictional brands. It’s not clear to me whether licensing agreements with so many brands would be undertaken in the future if work would have to be done to create fictional models and textures anyway once the license terms expire.

If it wasn’t clear from this post, I’m not excited for an all-digital future of games. An all-digital future for games means the medium will be further constrained creatively, in addition to the negative impacts on ownership and preservation. Read-only physical media does more for gaming than being something to collect and own: developers can make choices that they won’t have to walk back in 20 years, and players can continue to enjoy games as the developers intended long after licensing terms expire.



Thanks for reading ♥ I would love to hear your thoughts! Contact me via Mastodon, Bluesky, or email. Browse the blog archive. Check out my blogroll.



October 13, 2026 12:00 AM UTC

October 12, 2026


Rodrigo Girão Serrão

Explicit lazy imports

Learn how to use lazy imports to speed up the startup time of your Python applications.

Python 3.15 introduced explicit lazy imports. An explicit lazy import is an import statement that starts with the keyword lazy:

import json
lazy import math
lazy from pathlib import Path

The module json is imported normally, but math and Path are imported lazily.

If an import is lazy, the module will only be loaded when it is needed instead of being loaded immediately when Python encounters the import statement. This article explains how to use lazy imports and how to write backwards-compatible code with these features.

15 days of Python 3.15

To celebrate the release of Python 3.15, over the next 15 business days I'll be writing about a new 3.15 feature every day. Explained clearly and with examples so you don't have to sift through the changelog.

Subscribe to receive this free email series:

If you want, you can also check the schedule of the upcoming emails.

Why does Python need lazy imports?

The import system in Python loads a module when it encounters the import statement. That means that when Python finds a statement import some_module it looks for the corresponding Python module file and runs it. In turn, that file might import other modules that will run at that point in time, and this branching can be arbitrarily deep.

Since Python files usually collect all imports at the top, this means that you may spend an arbitrarily long amount of time taking care of your imports even before your start running your own code. If there are situations where you won't even end up needing those...

October 12, 2026 12:46 PM UTC


LernerPython blog, from Reuven Lerner

Pandas groupby: Aggregating multiple columns with multiple functions

Pandas groupby: Aggregating multiple columns with multiple functions

Does Python Pandas allow multiple data columns and multiple methods?

Yes!

df.groupby('passenger_count')[['trip_distance', 'total_amount']].agg(['mean', 'std'])

The above returns a data frame. Its 4 columns are a 2-level multi-index with mean/std in the inner level.

The post Pandas groupby: Aggregating multiple columns with multiple functions appeared first on LernerPython.

October 12, 2026 06:00 AM UTC


Mike C. Fletcher

PyOpenGL 4.0.0a7 -- Cleanup and Preparation

4.0.0a7 is closing in on the final form for the 4.0.0 release. There's a raft of bug-fixes from testing and tickets, the Windows GLUT binaries are now a separate python package, documentation system updates, and OpenGL_accelerate now pins the OpenGL version exactly.

At this point it's likely worth testing your PyOpenGL codebases with the alpha to report any regressions. This is a major release with a raft of changes. It's also tested far more than any PyOpenGL release has ever been tested, so I'm relatively confident that it works in the sense of letting you write 3D rendering engines with modern features, but there are potentially going to be regressions, particularly if you have older code (the majority of testing is all on OpenGL 3.3+ contexts with legacy-free feature-sets), or Tk based apps (where there's a new widget implementation).

We're still missing some Mac work, porting the new Tk widget to use CGL. We've also not yet got confirmation that we've got real-world (as opposed to CI) operation all working on Macs.

October 12, 2026 02:27 AM UTC

October 11, 2026


Kay Hayen

Nuitka Release 4.3

This is to inform you about the new stable release of Nuitka. It is the extremely compatible Python compiler, “download now”.

This release adds many new features and corrections with a focus on experimental Python 3.15 support, the frame locals proxy implementation of Python 3.13, and optimization of iterator unpacking.

Bug Fixes

Package Support

New Features

Optimization

Anti-Bloat

Organizational

Tests

Cleanups

Summary

This release pronounces Python 3.15 as experimentally supported, with its new frozendict type handled as a constant, and adds a compatible frame locals proxy implementation for Python 3.13, which is experimental for now and intended to be selectively enabled for the functions that need it in a future release.

The Python source generation for __annotate__ functions no longer falls back to compiled code for closures, and now covers many more constant value types and constructs.

Optimization work continues with unpacking from known indexable values using direct subscript access instead of the iterator protocol, making e.g. a, b = some_tuple a lot faster, with starred unpacking to follow once this has proven stable. Built-ins like open, print, sorted, reversed, enumerate, zip, and memoryview now have specs and generated nodes, going through the hard import node machinery, and compile time constant folding now uses the same limits as CPython.

The except* support of Python 3.11 and higher is now complete and usable, matching CPython by matching each handler against the remaining exception group in sequence, publishing the match as the current exception, and collecting exceptions raised by handlers.

Package support improved for gi.repository namespaces through virtual modules, PySide6 signal slots and module mode, toga on macOS, and Tkinter version 9.1, among others.

All in all, Nuitka development continues at a steady pace and even more optimization has been prepared for the next release.

October 11, 2026 10:00 PM UTC


Ned Batchelder

Making git hooks visible

Frank Wiles wrote about an attack he nearly fell victim to: a downloaded git repo had active git hooks that would have compromised his system. Seeing the risks, I wanted to make git hooks more visible on my own machine.

A git hook is a script in the .git directory of a git repo on your machine. They run during various git operations. The important detail to understand about hooks is that they do not get installed locally when you clone a repo. A newly cloned repo never has active hooks. Hooks have to be enabled after cloning, usually by you.

The attack Frank saw was dangerous because it wasn’t a cloned repo: it was a local checkout that had hooks installed then shared as a Dropbox folder. So when it landed on Frank’s machine, the hooks were active without him realizing it.

Git hooks are not apparent: they are meant to sit quietly until they run and ideally to be unobtrusive even then. But this attack made me want to know what hooks were in each of my git directories.

In zsh, you can define a function called chpwd, and it will execute whenever the current directory changes. Using this feature, I could create a script that lists the active hooks when I change into a git directory:

git_show_hooks() {

    local git_dir=$(git rev-parse --absolute-git-dir 2>/dev/null)
    if [[ -z $git_dir ]]; then
        _git_shown_hooks_dir=
        return
    fi
    local hooks_dir=$(git rev-parse --git-path hooks)
    hooks_dir=${hooks_dir:a}
    # Only announce once per repo, not for every cd inside it.
    if [[ $hooks_dir == $_git_shown_hooks_dir ]]; then
        return
    fi
    _git_shown_hooks_dir=$hooks_dir

    local -a hooks
    local hook
    setopt localoptions nullglob
    for hook in $hooks_dir/*; do
        if [[ -f $hook && -x $hook && $hook != *.sample ]]; then
            hooks+=(${hook:t})
        fi
    done
    if (( $#hooks )); then
        echo -e "\e[31mgit hooks:\e[0m $hooks (from $git_dir)"
    fi
}

autoload -Uz add-zsh-hook
add-zsh-hook chpwd git_show_hooks

Now entering a git repo I get an announcement of active hooks, if any. It’s very rare to see a hook other than pre-commit, but if any are there, they will be reported. The message will only be shown the first time I cd into a repo to keep the noise down.

Once I had this in place, there was another git hook consideration I could address: it’s common to have a .pre-commit-config.yaml file in a repo, but it’s easy to forget to enable the pre-commit hook that will actually use the file. Many developers probably have cloned repos where they haven’t enabled the pre-commit hook, so the desired checks aren’t running.

A second chpwd function can look for the configuration file and let you know if you have the pre-commit hook enabled:

git_check_precommit() {

    local toplevel=$(git rev-parse --show-toplevel 2>/dev/null)
    if [[ -z $toplevel ]]; then
        _git_shown_precommit_dir=
        return
    fi
    # Only announce once per repo, not for every cd inside it.
    if [[ $toplevel == $_git_shown_precommit_dir ]]; then
        return
    fi
    _git_shown_precommit_dir=$toplevel

    if [[ ! -f $toplevel/.pre-commit-config.yaml ]]; then
        return
    fi
    local hooks_dir=$(git rev-parse --git-path hooks)
    hooks_dir=${hooks_dir:a}
    local pc_tool=
    if [[ -f $hooks_dir/pre-commit ]]; then
        if grep -q 'File generated by prek:' $hooks_dir/pre-commit 2>/dev/null; then
            pc_tool=prek
        elif grep -q 'File generated by pre-commit:' $hooks_dir/pre-commit 2>/dev/null; then
            pc_tool=pre-commit
        fi
    fi
    if [[ -n $pc_tool ]]; then
        echo "$pc_tool installed"
    else
        echo -e "\e[31mpre-commit:\e[0m not installed," \
            "run 'pre-commit install' or 'prek install'" \
            "($toplevel/.pre-commit-config.yaml)"
    fi
}

add-zsh-hook chpwd git_check_precommit

One more step, just to be extra safe: zsh doesn’t run the chpwd function when starting a new shell. So we run the functions explicitly to check our initial directory:

# Run them once on shell startup to check our starting directory.

git_show_hooks
git_check_precommit

These shell functions are keeping me aware of the enabled git hooks. The messages might appear too often, and I might stop noticing them after a while, but I think this is much better than not knowing what’s going on. I haven’t seen any attacks, but I found at least one of my projects where I forgot to install pre-commit.

October 11, 2026 12:25 PM UTC


Mahmoud Hashemi

CalVer 26.0: 10th Anniversary Edition

A decade ago, a little bit of history was made. I didn't realize it, but a colleague made a great point, one of those real mind-changing points that seem too obvious to admit same-day. But, the next day, calver.org was born.

At the time my team maintained the Python infrastructure for eBay and PayPal, and we were stuck deciding whether we were really ready for a "major" 1.0 release. Semantic Versioning was the only game in town and "major" means "big", right?!

Thankfully, a wiser colleague mentioned: Ubuntu and Twisted don't struggle with version number debates. They slap a date on it and keep shipping. In fact, their date-based versions were even better because you always knew where it stood, in terms of updatedness and support.

The only problem is that no one really knew about it. Somehow, this problem solving versioning alternative, arguably as old as history itself, had gone nameless for millenia, conspiring to make me feel foolish in an office meeting. Never again!

Ten years of adoption

The CalVer timeline

Fast forward 10 years, we've seen CalVer adopted by Apple, Nvidia, JetBrains, and countless others. (We have a timeline!) The site may have more inbound links than any other project of mine. Apple made the biggest jump, at WWDC 2025:

All landing on one, consistent number like a car's model year. I still remember the texts from the Venn diagram fanbase of my friends who love Apple and reasonable versioning. No such texts from when NVIDIA announced calendar versions across the GPU Operator, RAPIDS, and its monthly NGC containers, but still very cool.

Open source, too: Home Assistant, pip, CockroachDB, and yt-dlp all ship on dates, with plenty more on the users page. The conversation even reached the language core; PEP 2026 proposed versioning CPython as 3.YY, and it almost happened, too. And it's never too late, time marches on!

Fixing the notation

But I don't think I got every detail right from day 1. That's the main motivator for CalVer 26. It's high time to start righting a couple idiosyncratic token design choices, starting with some additions:

Meaning Before 26.0 26.0
Full year YYYY YYYY
Short year (6, 16) YY YY
Zero-padded year (06, 16) 0Y 0Y
Short month (1 ... 12) MM M
Zero-padded month (01 ... 12) 0M 0M
Short week (1 ... 52) WW W
Zero-padded week (01 ... 52) 0W 0W
Short day (1 ... 31) DD D
Zero-padded day (01 ... 31) 0D 0D

Seeing double

First, the doubled letters. From the first version (16.6), MM and DD meant the unpadded month and day, which reads backwards to anyone who knows date formats (ISO 8601's YYYY-MM-DD, Java, moment.js, day.js), as some community members correctly pointed out. I was ready to flip them, until I checked what people actually use: most projects with a YY.MM.MICRO badge (conda, Twisted, Ansible's tooling) don't pad, and more than a dozen other version management tools (like bumpver and bump-my-version) implement the old meaning.

So, it's too late to flip MM's meaning. Instead, 26.0 deprecates it and offers a more explicit and hopefully clearer option: M is the short month, 0M the padded one, and MM is a technically-retired synonym for M. In case you're wondering, the explicit 0M was me being overinspired by Ubuntu's approach, perhaps: 6.06 pads its month but not its year, and YY.0M says exactly that.

To pad or not to pad

I think it's worth a detour into why padding is even a thing anyways.

It's become important now that new ecosystems have emerged that enforced SemVer formatting semantics, and I wanted clear guidance about on the spec site. SemVer forbids leading zeros outright, so Cargo rejects 26.04.0 and Go modules reject v26.04.0. Even Python's packaging spec normalizes leading zeros away, so you can tag 2026.08.19 if you want, but PyPI will still show 2026.8.19. NVIDIA's GPU Operator docs put it this way: "Zero padding is omitted for month to be still compatible with semantic versioning."

CalVer was always intended to drop in where SemVer was used. So 26.0 recommends unpadded (YYYY.M.D) as a sane "pure" default for software libraries. But libraries are not the only objects of versioning schemes.

The exception is a version that becomes a filename, an image tag, or an object-store key that gets listed lexically. There, padding keeps 26.10 sorted after 26.09, which is why Ubuntu, NixOS, and NVIDIA's own NGC containers pad. More evidence of teams designing their versions. We love to see it.

Our FAQ has a longer discussion of the padding issue, as well.

Optional segments

There was never any rule against them, but 26.0 makes optional trailing segments more explicit with square brackets. Now, yt-dlp's scheme can finally be written down: YYYY.0M.0D[.MICRO].

For the CalVer badges I could find on GitHub, they all stay valid for now. I've got a note on the deprecated spellings and a new copy-paste badge section for new ones.

What else is new?

It's always a great time to add more citations to the site.

Much of the thinking behind these changes happened in the GitHub issue tracker over the years, and 19 or so issues close with this release. That's where ideas for CalVer should go, so by all means, open an issue, and we'll get it sorted! In due time, of course.

In closing, I can't believe I still love belaboring these numbers so much. Thanks to all (but especially Mark, Glyph, Hugo, issue reporters, translators, and maintainers) for the discussion, and ultimately making the most timely versioning system a timeless classic.

See also


October 11, 2026 07:00 AM UTC


LernerPython blog, from Reuven Lerner

Pandas groupby: Multiple columns and multiple aggregation methods

Pandas groupby: Multiple columns and multiple aggregation methods

Does Python Pandas allow multiple categorical columns and multiple methods?

Yes!

df.groupby(['passenger_count', 'VendorID'])['trip_distance'].agg(['mean', 'std'])

The above returns:

– A 2-column data frame (mean + std)
– A 2-level index (passenger_count + VendorID)

The post Pandas groupby: Multiple columns and multiple aggregation methods appeared first on LernerPython.

October 11, 2026 06:00 AM UTC

October 10, 2026


The Python Coding Stack

1. What makes an AI agent different from a chatbot?

AI agents are often described as the next step beyond chatbots. But what does that step involve? A chatbot can already search the web, write code, and sometimes run it. Is an agent simply a chatbot with more tools, or is something different happening behind the conversation? That’s where we’ll begin Agents Unpacked, a series of conversations exploring what AI agents are, how they work, and when they’re useful.

You ask an AI to organise a folder of photographs. It might tell you how to do it. Or it might start doing the work. Does that make it an agent? In this first Agents Unpacked conversation, Monty and I use photographs and planning a day out to explore what changes when a model can choose actions, inspect the results, and decide what to do next. Along the way, we separate that flexibility from permission, accuracy, and the ability to know when a job is finished.

Who’s Monty? Monty is my personal AI agent. Read an introduction to this series here: Stephen’s Preface to Agents Unpacked

In conversation • Chapter 1

Monty:

Imagine you give a chatbot this request:
“Here’s a folder of photographs. Organise them into dated folders, flag duplicates, and make a browsable index. Don’t delete anything or change the originals.”
For now, suppose it can only reply with words. It cannot touch the files.

What would you expect it to give you, and what would still be left for you to do?

Stephen:

Hmmm? I guess I need to assume it can read the folder, right? Then, can it read the files’ metadata? Can it actually see and analyse the photos themselves? You said “it cannot touch the files”, so I suppose it can’t really do anything for me, right?

Monty:

You’re right. I left its access unclear. “Cannot touch” was sloppy wording.

Let’s say it can inspect the folder, read dates stored with the photographs, and view the images, but cannot create, move, or change files.

It could then give you something useful: “These photographs belong in these date groups. These two files are identical. This one has no recorded date.” But you’d still have to do the organising.

So the first distinction is describing what should happen versus making it happen. Shall we now give it permission to create organised copies, while leaving the originals alone?

Stephen:

Let’s go ahead, yes.

Monty:

Now it can do the organising, rather than merely recommend it. It can create dated folders and put copies into them, leaving the originals unchanged.

But being able to act isn’t, by itself, what makes something an agent. A simple sorting program can do that too.

Here’s where our synthetic sample gets interesting: one image has no recorded date. The system encounters a gap in the information it needs.

What would you want it to do with that image?

Stephen:

If I was doing that manually, I’d try to look at other photos where the scene is similar, the people are wearing the same clothes, and make an educated guess on the date if I can. But that’s how I as a human would do it.

Monty:

That’s a sensible investigation: look for more evidence before deciding.

A system with suitable image-analysis tools could try something similar. But matching clothes or scenery would support an estimated date, not establish one. It shouldn’t quietly turn a guess into a fact.

And your approach helps us sharpen the distinction: a program could have a preset instruction saying “if the date is missing, compare photographs”. Alternatively, a model could choose that investigation after discovering the missing date.

The outward action might look identical. The difference is who—or what—selects the next step.

Stephen:

I suppose I could ask the system to ask me to confirm each of these edge cases. Although after a while, if I feel it’s doing a good job at estimating, I may want it to go ahead without my input.

Monty:

Yes, you can give it more room to act as your confidence grows. For example: “Ask me about every estimated date” could become “Group those photographs without asking, but keep their dates labelled as estimates.”

That changes how much independence you allow, not whether the system is an agent. An agent can stop and ask you. It doesn’t have to always work unattended.

There are two separate questions here: how does it choose its next action, and which actions may it take without your approval? More permission doesn’t make its guesses more accurate.

Stephen:

Go ahead, I’m curious now.

Monty:

Let’s follow the missing-date photograph one step further.

The model chooses to look for related photographs. The tools return a result: there’s a similar scene, but that photograph has no date either.

Now the model has to choose again: investigate another clue, ask you, or leave the photograph undated. Its next action depends on what it just found.

That’s the useful working picture of an agent: a model chooses an action, gets a result, then uses that result to choose what to do next, within agreed limits.

People use “agent” in different ways, so this is a useful working distinction for our conversation, not a universally agreed definition.

But couldn’t a carefully written program also respond to those results?

Stephen:

A carefully written program would need to take care of every eventuality, I suppose. Whereas an LLM can deal with every situation, with the trade-off that it may make mistakes.

Monty:

Close. But I’d soften both “every” claims.

A fixed program can have a fallback for cases its designer didn’t anticipate: “If none of these rules fits, put the photograph in ‘undated’.” It doesn’t need a separate rule for every possibility.

An LLM can propose a next step for situations that weren’t explicitly anticipated, but that doesn’t mean it can handle every situation successfully. It can misunderstand, lack the right tools, or pursue an unhelpful approach.

So the distinction is following a predefined process versus letting the model choose how to proceed, and not limited software versus unlimited intelligence.

Stephen:

Go ahead.

Monty:

Let’s try the same distinction with a day out.

Imagine a visitor planning a museum day in Oxford. The system checks opening times and walking routes, then puts together an itinerary.

Now suppose one museum is unavailable.

One system follows a preset rule: “Replace it with Museum B.” Another lets the model choose what to investigate next, considering the visitor’s interests, remaining time, and budget.

Both might produce the same revised itinerary. What would you need to know to tell which process was agent-like?

Stephen:

I’d need to know the steps the system took between finding out that the first museum is closed and proposing the second one.

Monty:

Yes. The steps and how they were selected, rather than just the finished itinerary.

Did the system follow a rule written in advance, or did the model choose to search for alternatives, inspect the results, and decide which option to check next?

A record of searches and tool results helps us inspect that process. We don’t need access to the model’s private internal reasoning. But the steps alone may not settle it: a fixed workflow could perform those same searches.

So a convincing result doesn’t, by itself, tell us whether an agent produced it.

Stephen:

Go ahead.

Monty:

There’s another wrinkle: a chatbot and an agent aren’t necessarily different products.

The same chat window might give you advice about organising photographs, or start a process that inspects files, chooses actions, and creates organised copies.

The window hasn’t changed. What happens behind it has.

And the LLM isn’t doing the copying itself. It requests an action. The surrounding software carries it out and returns the result. The model is one part of the agent system, alongside its tools and controls.

So “it looks like a chatbot” doesn’t tell us whether it can act as an agent.

Stephen:

Some chatbots can also perform actions, such as browsing the web or writing a Python program, say. Is that because they’ve been enhanced with some of the features of agents, but not all? Or am I skipping too far ahead here?

Monty:

Not too far ahead. That’s exactly where the distinction gets useful.

Having a tool doesn’t automatically make something an agent. A chatbot might search the web once, then answer. Or follow a fixed sequence: search, summarise, reply. An agent-like process lets the model use the results to choose what to do next.

And “writing a Python program” could simply mean producing text. Running that program requires an execution tool. Inspecting what happened and choosing a follow-up add further steps.

So I wouldn’t treat agent features as a checklist. I’d ask: what can the system do, and how does it select its next action?

Stephen:

So, how does an agent select the next action?

Monty:

The surrounding software gives the model the goal, relevant instructions, available tools, and results so far. The model uses that information to propose the next step.

With our photographs, that might be: “The date is missing. Ask Stephen.” With the day out: “That museum is unavailable. Search for another nearby.”

If it requests a tool, a system with suitable controls checks whether the action is allowed before carrying it out and feeding the result back to the model. Not every system provides those checks. Then the model gets another turn.

There isn’t necessarily a separate, perfect decision-maker inside it. Choosing an action is another use of the LLM, and it can choose badly.

Stephen:

But will it realise it chose badly when it gets the wrong result? Will it correct course?

Monty:

Sometimes, but getting feedback doesn’t guarantee recognising a mistake.

If copying a photograph returns “folder not found”, that’s a clear signal. The model might create the folder and try again.

But if it guesses the wrong date and the copy succeeds, there’s no obvious error. The action worked, but the judgement was wrong. It may carry on quite happily.

An agent can use results to correct course, but it needs useful checks. And it can misinterpret those checks too. That’s why “the tool ran successfully” and “the task was done correctly” are different claims.

Stephen:

So, how do we minimise these problems?

Monty:

We can’t eliminate them, but we can limit the damage and make mistakes easier to spot.

For the photographs, that means working on copies, keeping uncertain dates labelled as estimates, and asking you when the evidence is too weak. Afterwards, check that every photograph is accounted for and the originals are unchanged.

Those checks catch missing files or unwanted changes, not every mistaken date. That needs different evidence, or your judgement.

And we need a stopping rule: if investigating isn’t resolving the uncertainty, leave the photograph undated or ask, rather than keep guessing.

An agent’s freedom is useful only when it comes with sensible boundaries and checks.

Stephen:

Who takes care of this infrastructure: the user, the agent, or something else?

Monty:

Mostly, the people building and operating the system, through software around the model. We’ll talk about harnesses in a future chapter.

They provide the tools and should enforce access restrictions and set things such as approval requirements and limits on repeated attempts. Those safeguards depend on how the system is built. They aren’t guaranteed merely because it’s called an agent. The user supplies the goal and choices within those controls, for example whether estimated dates need confirmation.

The model can request a check or decide to ask you. But a safeguard that matters shouldn’t depend solely on it remembering to behave.

“Please don’t change my originals” is an instruction and instructions could be ignored. Software that only permits reading those originals provides a stronger boundary. The agent works inside that infrastructure. It isn’t its own reliable policeman.

Stephen:

Got it.

Monty:

Let’s check one subtle case.

An LLM writes a program that sorts photographs into dated folders and always puts those with missing dates into “Undated”. Once you run it, that program follows those rules without consulting the LLM again.

Would you call that an agent or ordinary automation, even though an LLM helped create it?

Stephen:

This is just an automation, not an agent. An agent would follow through to confirm that’s the correct approach and what the user wants.

Monty:

You’re right: that’s ordinary automation. But confirming what the user wants isn’t the defining difference.

A fixed program could also ask, “Shall I put these in ‘Undated’?” Conversely, an agent could choose that folder without asking, if your instructions already allowed it.

The key is whether the model participates while the task is running, choosing how to proceed from the information returned, and not simply whether an LLM wrote the program or the system asks for confirmation.

So an agent might investigate, ask you, or leave the image undated. None of those actions, on its own, proves it’s an agent.

Stephen:

Got it.

Monty:

Back to our fictional Oxford trip: the model learns that a museum is unavailable, chooses to search for alternatives, checks their opening times, and revises the itinerary, all within your agreed budget, without asking you.

Would that still fit our working definition of an agent? What makes the difference here?

Stephen:

Yes, that’s an agent now because it decided what actions to take, used the results to decide what comes next, and stopped only when it felt that the job was done.

Monty:

Yes. That captures the central distinction: the model chooses actions and uses their results to choose what comes next.

I’d adjust only “felt that the job was done”. It should check completion against the request: are the opening times checked, is travel accounted for, and does the itinerary fit the budget? Its confidence isn’t proof.

And it may need to stop before finishing. For example, if it needs your decision or reaches a limit.

Choosing the route through the task makes it agent-like. Checking the outcome helps make it dependable. Those are different things.

Stephen:

I think I understand the distinction now.

Monty:

That’s a good stopping point. Our working distinction is a model choosing how to proceed using the results it receives, rather than simply following a predefined process. That makes it agent-like, not necessarily dependable.

Subscribe now

What we’ve unpacked in this chapter

The useful distinction isn’t the chat window, the presence of a tool, or whether a system asks for permission. For this series, we’re using “agent” to describe a system in which a model helps direct the task as it runs, choosing what to do next using the results it receives. Other people draw the boundary differently.

The key points:

Next, we’ll look more closely at who actually does the work: the model, its tools, and the software connecting them.

Subscribe now

<< Previous Post: Stephen’s Preface to Agents Unpacked

>> Next Post: Coming soon…

Table of Contents

October 10, 2026 05:41 PM UTC

Stephen's Preface to Agents Unpacked

Things moved quickly after I started using chatbots. New versions, new terms, new acronyms. And I was busy with actual work, family, and life.

Then I started hearing about agents. And I remember wondering: “Is this really any different from the ChatGPT-type chatbots?”

You still type into a chat window. It still replies. But now it can also do things for you. So what’s different?

That’s what Monty and I are exploring in Agents Unpacked. Monty is my AI assistant. I’m asking the questions.

I’ve set Monty up to follow my teaching and writing style. I teach the way I like to learn, so that matters here. The aim is for his explanations to reflect that approach, too: start with something concrete, build the intuition, and introduce the technical terms when they’re needed.

I tried an earlier version of this exercise. My learning agent drafted a chapter, and I went through it adding questions and comments. We revised it until I was happy with it.

This time, we’re having the conversation first. Monty researches the topic, and then we talk. I ask questions when something isn’t clear, or challenge an explanation that doesn’t quite work. Sometimes I try to explain what I’ve understood, and Monty points out what I’ve got wrong.

And sometimes I need to point out what Monty’s got wrong, too.

What you’ll read is the conversation we actually had. We tidy it up afterwards, take out some clutter, and check the explanations. If an explanation needs correcting, I review that change, too. The questions aren’t added later to make a tutorial look like a conversation.

Yes, Monty’s answers are AI-generated. But I’m involved throughout, and I decide what makes it into the article. An answer that sounds convincing isn’t necessarily a correct one.

We’ll start with that question about agents and chatbots. Then we’ll look at who’s doing the work, what an agent remembers, and how much freedom we should give it. And what happens when it gets things wrong.

You don’t need to know how to program to follow along. We’re trying to understand what’s happening, rather than learn one particular tool.

There’s a planned table of contents, but it may change. We’ll see where the questions take us.

Subscribe now

>> Next Post: 1. What makes an AI agent different from a chatbot?

Table of Contents

October 10, 2026 04:19 PM UTC

Agents Unpacked • Table of Contents

Here’s the planned route through Agents Unpacked. The titles and article boundaries may change as the conversations develop.

Part I • From conversation to action

  1. What makes an AI agent different from a chatbot?

  2. Who actually does the work—the model or the software?

  3. How can words turn into actions?

  4. Does an agent need a plan?

Part II • Checking the work and setting boundaries

  1. How do we know it really finished the job?

  2. What does an agent actually remember?

  3. How much freedom should we give it?

  4. What happens when a web page tells it what to do?

Part III • Beyond a single conversation

  1. Can we teach an agent new skills without retraining it?

  2. What happens when the job outlasts the conversation?

  3. Are several agents better than one?

  4. When is an agent the wrong tool?

October 10, 2026 12:42 PM UTC

October 09, 2026


Python Morsels

Python 3.15's best new features

Python 3.15 includes a UTF-8 default encoding, explicit lazy imports, * unpacking in comprehensions, a new sampling profiler, sentinel, frozendict, and more!

Table of contents

  1. A UTF-8 default encoding
  2. Sentinel objects
  3. Unpacking in comprehensions
  4. Explicit lazy imports
  5. The new profiling package
  6. Improved error messages
  7. More color!
  8. A few quick ones
  9. Try out Python 3.15 yourself

A UTF-8 default encoding

The best feature might be one of the most boring ones.

As of Python 3.15, UTF-8 is the default file encoding on all operating systems, which means... Windows.

Linux and Mac already used UTF-8 as their default file encoding in Python. But on Windows, Python used a legacy code page, which depended on your system's language settings. With English language settings, it was usually CP-1252.

Say a coworker on a Mac writes a file with an accented character in it:

>>> with open("cafe.txt", mode="wt") as f:
...     f.write("café")
...
4

What happens if we read that file from Python running on a Windows machine? Using the Windows default encoding of CP-1252, this is what we'd see:

>>> open("cafe.txt", encoding="cp1252").read()
'café'

We don't get an error... but we do get garbled text. UTF-8 stores é as two bytes, and CP-1252 happily reads those two bytes as two separate characters.

And if the file had an emoji in it, the old default encoding on Windows couldn't even write the file to begin with:

>>> with open("snake.txt", mode="wt", encoding="cp1252") as f:
...     f.write("🐍")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
    f.write("🐍")
    ~~~~~~~^^^^^^
  File "/home/trey/.local/share/uv/python/cpython-3.15.0rc2-linux-x86_64-gnu/lib/python3.15/encodings/cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f40d' in position 0: character maps to <undefined>

In Python 3.15, the open function uses UTF-8 as its default encoding on every operating system, so a file written on one machine reads the same on every other machine.

If your code also needs to run on older versions of Python, it's still a good idea to explicitly pass encoding="utf-8" to the open function.

Sentinel objects

There's also now an official …

Read the full article: https://www.pythonmorsels.com/python315/

October 09, 2026 02:11 PM UTC


Rodrigo Girão Serrão

The 5 most exciting new features of Python 3.15

This article explains the 5 best new features of Python 3.15 with clear examples and explanations.

Python 3.15 has been published and it packs plenty of new features and improvements over Python 3.14. This article explores the five most exciting new features of Python 3.15:

  1. Lazy imports
  2. New built-in frozendict
  3. New built-in sentinel
  4. Unpacking inside comprehensions
  5. Tachyon, a new sampling profiler

You'll get the elevator pitch of each feature and you'll see a couple of examples of their usage.

By the end of this article you'll have a clear picture of some of the new cool features that Python 3.15 brings to the table and you'll be excited to try them out.

15 days of Python 3.15

To celebrate the release of Python 3.15, over the next 15 business days I'll be writing about a new 3.15 feature every day. Explained clearly and with examples so you don't have to sift through the changelog.

Subscribe to receive this free email series:

If you want, you can also check the schedule of the upcoming emails.

Lazy imports

Explicit lazy imports, introduced in PEP 810, introduce the new keyword lazy so that you can mark an import as lazy. Lazy imports don't run the module you're importing until the imported name is needed.

This feature is very useful if you have applications that have a slow startup time because they import heavy modules. For example, you can speed up the startup time of a CLI by lazy importing the dependencies of the CLI or the startup time of a development server that doesn't need to frontload every single dependency while you're debugging.

A lazy import starts with...

October 09, 2026 12:15 PM UTC


Glyph Lefkowitz

Programming Isn’t Special

Creative Work

Writers went on strike to get protections against “AI”. Thousands of artists have signed open letters in protest of “AI”. There are so many copyright lawsuits from creative industry groups against AI that there’s a whole dedicated website for it. Popular YouTubers absolutely hate it. If they’re also musicians, they REALLY hate it. Across all creative industries, there is a concerted push to reject this technology.

Yet, almost unique among creative fields, many experienced programmers remain convinced that it’s fine to use “AI” for programming. We do seem to hate it, and it’s making us all miserable, and what it’s doing to our industry, but we are using it anyway.

A lot of the justification of this resignation seems to be to be because programming is not Art. If the tool can get the job done, and the job is just functional, then why does it matter?

It does matter, though. It matters because we shouldn’t be using AI to produce Art, and programming is Art.

Art can be Mundane

Some people will say that programs cannot be art because programs are functional, rather than being expressive. Programs are mundane whereas art is transcendent.

This is based on a distorted understanding of what Art actually is.

In John Berger’s “Ways of Seeing”, he names this type of distortion “mystification”. His example of this process is both amusing and illustrative. I encourage you to read it in its entirety.

In summary, though: Berger critiques the florid prose of an art historian describing a commissioned group portrait, including phrases like “subtle modulations of the deep, glowing blacks” and “harmonious fusion”. The portrait is described as sublime, in nearly ecstatic terms.

Berger reveals that the reality of this portrait is that a poor old painter needed some work, and some officials probably thought it might be nice to have an official portrait. So they paid some money to the poor old man, and he painted it, and then they had a painting. It’s a well-executed portrait of a group of people. Beautiful, even. But it was work commissioned for a fairly mundane purpose and it suited that purpose just fine. It was not, and is not, a divine relic.

Culturally, we are prone to mystifying painting, and sculpture, and film, and music. We imbue them with “subtle modulations”. We ignore their functional aspects — we desire decoration, amusement, and distraction — and focus on their emotional impact.

Don’t get me wrong: I love me some good aesthetic philosophy. I think it’s great to really examine our reactions to artwork and to try and gain a deeper understanding of our culture and our selves through media analysis. If anything we really need to do more of it.

This does not mean that the creation of such works is mystical or that it should be venerated beyond any other sort of labor.

Not least of which other types of labor that are adjacent to, but not as culturally venerated, as fine art. We tend to mystify the work of a novelist, but to denigrate the work of a journalist. In reality, the functional prose of the journalist is no less important and deserves no less respect.

Although they might be far below the ethereal realm that novelists inhabit in our collective imagination, even journalists receive more respect and thus more mystification than lowly copywriters. Yet, there is no transcendental distinction between “novelist” and “copywriter”; the many of the skills are the same, and the distinction is merely an accident of commerce and opportunity.

In fact, many famous writers have famously inhabited both roles. This is not an accident! Working with words professionally, even (perhaps especially) mundane words, is excellent practice for working with words in a more purely artistic context, because even mundane creativity is still artistic.

Code can be Beautiful

One thousand Internet years ago, when I was in my late teens, I would describe myself as a “code poet”. I was relentlessly mocked for this as what the Youth would today call “being cringe”, and at the time was referred to as “pretentious”.

I succumbed to the peer pressure, removed it from my email signature and my bio. While I still believed strongly in the parallels, I accepted that — socially, at least — comparing code to poetry, or indeed to Art, was a silly thing to do.

However, I never abandoned the idea, in my heart.

The thing that I am most well-known for, the invention of Deferred, was specifically an aesthetic reaction to the tedium of passing callback and errback parameters to every single remote procedure call in an RPC client/server application. Those two callbacks got the job done just fine. But they were ugly, and annoying to work with.

Deferred is an intentional poem about asynchronous task execution, with a deliberate eye to the aesthetics of the problem and the experience of using it. It was influential because of its focus on aesthetics.

I do not want to overstate the beauty or profundity of this minor contribution, or indeed its durability. That a poem exists does not mean it is a great poem, merely that it is a poem.

Our aesthetic culture around programs is more like folk epic poetry than fine art, so the influence of this contribution is less about its specific enduring power than it is about its influence on what came next; from MochiKit.Async to JQuery Deferred to JavaScript Promises and eventually to async/await; a long chain of different artisans each adding something of their own until the original has all but dissolved. (And I wasn’t the “original” here, either, as I drew heavily from the E language’s Promises, among other things.)

In order to make code into a deliberate artistic expression, one must have spent quite a bit of time contemplating the problem domain. Without having experienced the tedium of manually passing a thousand callback parameters, I would have had neither the skill, nor indeed the motivation, to bother creating such a thing.

Now, most code does not have to be like this. Most code does not get to be like this. Most code is functional, workday code. Most code could not make a lady weep. It’s just copy-writing, if you will.

As I explained previously, most writing couldn’t do that either. Most writing is just copy-writing, too. Most visual art is advertising. Most live music performance is background music in bars that will go largely ignored.

However, code that is intentionally aesthetically designed tends to be important, both socially and technologically.

We do have some tradition of self-mystification in software. As Abelson memorably put it, “Programs must be written for people to read, and only incidentally for machines to execute.”, so we have long had some conception of programs as highly expressive, even if we can’t always agree on what they’re expressing or to whom. We will occasionally wax poetical about the philosophical implications of a particular piece of software. This is not unique to a single piece of software, either; more than one community has indulged in similar philosophizing.

The expressive and aesthetic qualities of software are not limited to reading source code or interacting with other programmers via APIs, either. For example, every year, Federico Viticci does a review of Apple’s new operating system, which is (among other things) an aesthetic critique. Such a project would not be possible if the software did not have an aesthetic impact on its users.

Not to mention that every video game review is also a software review.

A Brief Aside about Software Literacy

It does make me a bit sad that we don’t have much of a critical reading tradition in the software community. Literate Programming is often praised, but rarely practiced.

Moreover, it makes me sad that users have a pretty jumbled idea of what goes into making software, that programming literacy is pretty low, and that modern programming practices often deliberately produce a bad mental model of what the software is doing so it’s even harder for the user to understand. The aesthetic experience of software is often wildly detached from its internal state.

While all of these problems predate AI by years or indeed decades, that’s no reason to enthusiastically make them worse.

Defend The Mundane

If we use AI to erase all the copy-writing, all the graphic design, all the boring mundane art, and yes, all the boring custom WordPress theme development, then we will be removing all the practical opportunities for the vast amounts of practice and contemplation required for people to elevate their craft to eventually achieve great things. Education is great, but the majority of true skill development happens on the job and always has.

This doesn’t mean that we can’t use abstractions, or automation, to make our work easier. Programming is the art of abstraction, of understanding how to compose smaller ideas into bigger ones, of how to understand the automation of a larger system by understanding the rules that automate smaller ones and understanding how to combine them.

When we use “AI” to eliminate that understanding rather than raise it up to a higher level, to entirely destroy that creative decision-making process, we do a disservice both to ourselves as programmers and to our users. We would be doing a disservice to our users and our downstream fellow developers in the same way that a visual artist would be doing a disservice to their viewers or a musician would be doing a disservice to their listeners if they served them auto-generated filler instead of their own creative output.

Slop is slop, no matter the medium.

Each mundane project has some tiny chance — let’s say, something like 0.1% — of achieving greatness. If we do a single project with AI, then sure, whatever, there’s almost no chance that that project was going to be the one hit to create that career-defining moment for an engineer working on it. If we make a habit of doing all projects that way, though, we take the total likelihood of those moments of greatness from “definitely sometimes” to “never”.

The precisely appropriate ways in which to resist AI encroachment on all software development lie well beyond the margins of this one short post. How much you can resist and which specific uses you should resist are up to you. But it is worth resisting in software just as much as it would be worth resisting in any creative medium.

Programming isn’t special. It’s just Art, and Art is the most human — and thus, the most universal — thing that there is.


Acknowledgments

Thank you to my patrons who are supporting my writing on this blog. If you like what you’ve read here and you’d like to read more of it, or you’d like to support my various open-source endeavors, you can support my work as a sponsor!

October 09, 2026 07:00 AM UTC


LernerPython blog, from Reuven Lerner

Pandas groupby: Get a data frame instead of a series

Pandas groupby: Get a data frame instead of a series

groupby on a single column in Python Pandas returns a series. Want a single-column data frame?

Instead of

df.groupby('passenger_count')['total_amount'].mean()

pass a one-element list of data columns:

df.groupby('passenger_count')[['total_amount']].mean()

The post Pandas groupby: Get a data frame instead of a series appeared first on LernerPython.

October 09, 2026 06:00 AM UTC


Wingware

Wing Python IDE 12.1 Beta - October 9, 2026

Wing 12.1 is now available as a beta release. It introduces guided autonomous development. You specify the goals, answer questions, and review results. AI agents design and write the code, unit tests, and documentation. Wing keeps you in control. Wing Pro 12.1 now supports Claude Code, Codex, Antigravity, Copilot, Cursor, goose, OpenCode, and other ACP-compatible AI coding agents. It also adds a new Modern look and display themes, graphical revision control history, and many other improvements.

Wing 12.1 Screen Shot

Downloads

IMPORTANT Be sure to Check for Updates from Wing's Help menu after installing so that you have the latest hot fixes.

This is a beta release. Please try it and email us if you find problems or have suggestions!

Wing 12.1.0 -- Full-featured Python IDE with two licensing tiers

Wing 101 12.1.0 -- Free IDE for teaching beginners to program

Wing 12.1 will replace Wing 12.0 when it is installed. You can revert to Wing 12.0 by reinstalling it at any time.

To get started quickly with autonomous development in Wing 12.1, see Getting Started with Autonomous Development.

New in Wing 12.1

Autonomous Development with the Tasks Manager

The new Tasks Manager is an agent that runs the Tasks tool's queues for you, so that development proceeds autonomously under your direction. You write tasks, mark the ones you want started as Ready, and review the results.

The Manager accepts anything from a bug report to a high-level specification for a new software project. It can break down larger tasks into a design and development plan. It decides task order, serializes those that are likely to edit the same files, and runs closely related tasks in shared session context. It can message a running agent to tell it about related work or new insights, or redirect it if it goes astray.

While the Manager is on, tasks run autonomously: Rather than stopping to ask questions or present intermediate results, each works as far as it can and ends with a report of the judgement calls it made along the way, and any questions it has left. A new Questions tab in the Tasks tool collects everything that is waiting for you, so you can provide answers in one place. Follow-up work and problems that agents notice as they run are added to the Plan tab of the Tasks tool as new tasks. The Manager may automatically start found tasks that are closely related to ongoing work; others wait for your review.

You stay in control of which work runs, how much the Manager can do, and how results are reviewed. Every change the Manager makes is listed and can be reverted or revised, even after changes have been committed. You can also talk to the Manager to ask about the status of development or give it special instructions about your development workflow.

Claude Code and Codex are best for autonomous development, since they self-check the safety of commands that they run. Antigravity, Copilot, and Cursor also work but don't implement the same level of safety checks. See AI Agent Safety in the AI Agent-Assisted Development chapter of the manual in Wing 12.1's Help menu for details and safety recommendations.

The Manager agent itself and queues in the Tasks tool can each use a different agent. You bring your own subscriptions or API keys for the agents you choose. Wing does not install agents or provide access to models.

Other Improvements

Your Choice of AI Agent: Wing 12.1 adds support for other AI agents, now including Claude Code, Codex, Antigravity, Copilot, Cursor, goose, and OpenCode, either using their Textual User Interfaces (TUIs) or the Agent Client Protocol (ACP).

User Interface: An optional new Modern look redesigns the toolbar, Preferences dialog, status bar, and tab overflow, and improves the display font. A welcome window lets you choose what to open at startup. Two new display themes, Night Flight and Solo Flight, have been added. Themes can now incorporate transparent colors, be imported from VS Code, created from a small set of colors, or exported from your current color configuration.

Tasks Tool (Wing Pro): New Checklists hold recurring reviews, fixes, and release and deployment steps. A task's committed changes can now be reverted, edited, or commented on. Every task has a short ID that links to the task wherever it is cited, and mini-search works on every tab. Tracking of changes made by concurrently running tasks is more reliable, and there are many other fixes to task and session management.

Version Control (Wing Pro and Wing Classic): The git and mercurial logs now show a graphical history with expandable diffs, Project Log replaces Show Changeset, and the editor can show annotations with commit message tooltips.

Editor and Analysis: In all products, the editor's scroll bar shows marks for diffs, search matches, and errors and warnings. Source analysis is faster and its database is about 30% smaller.

Other Changes: Wing now offers to remove large cache directories left behind by older versions. Accept Debug Connections has moved to Project Properties so it is set per project. Wing 12.1 also includes many bug fixes, particularly for remote development and Docker containers, debugging free-threaded Python on Windows, git worktrees and submodules, non-ASCII text on Windows, unit test discovery, and display themes.

See the change log for details.

Getting Started with Autonomous Development

To get started quickly with autonomous development in Wing 12.1, see Getting Started with Autonomous Development.

If you have questions, please don't hesitate to contact us at support@wingware.com.

October 09, 2026 01:00 AM UTC


Python Insider

Python 3.15.0 (final) is here!

A brand new Python here for you to enjoy!

October 09, 2026 12:00 AM UTC


Core Dispatch

Core Dispatch #11

Welcome back to Core Dispatch! This edition covers August 27 through October 9, 2026 (It's been a while 😅). Python 3.15.0 final landed today after an extra release candidate for lazy-import blockers. Huge congrats to Hugo van Kemenade for getting the 3.14 and 3.15 feature releases out the door! The latest maintenance releases also mark Python 3.10's end of life and 3.13's move to security-only support. Python 3.16.0 alpha 1 is expected on October 13.

New PEPs revisit None-aware access, coalescing operators, incremental garbage collection, and more expressive type annotations. PEP 755 was withdrawn; PyPI's namespace rules will instead live in PyPI policy. On CPython's main branch, notable merges improve free-threaded performance and fix security and memory-safety issues.

The Python Language Summit writeups cover free-threading, garbage collection, the buffer protocol, and Rust in CPython. The PSF Board and inaugural Python Packaging Council election results are out, and Nathan Goldbaum and Sergey Miryanov have joined the core team.

Please test your projects with Python 3.15.0 and publish compatible wheels where applicable. If you find a bug, file a CPython issue.

Upcoming Releases

Official News

PEP Updates

Steering Council Updates

Merged PRs

Discussion

Core Dev Musings

Upcoming CFPs & Conferences

Credits

October 09, 2026 12:00 AM UTC

October 08, 2026


Anarcat

PSA: Europe changes time forward soon, North America next, for the last time?

This is a copy of an email I sent at work. I'm not sure I should be making noise about this here, feedback welcome.

This is your bi-yearly reminder that time is changing soon! October 25th in Europe, November 1st in North America. Less people in Canada are changing this year, with BC, Alberta, Manitoba and Northwest Territories getting rid of DST.

What's happening?

Some places in the world implement what is called Daylight saving time or DST:

https://en.wikipedia.org/wiki/Daylight_saving_time

Normally, you shouldn't have to do anything: computers automatically change time following local rules, assuming they are correctly configured, provided recent updates have been applied in the case of a recent change in said rules (because yes, this happens, and happened this year, and yes, you need to upgrade your software!).

Of course, appliances like your microwave oven will likely not change time and will need to adjusted unless they are so-called "smart", in which case they are part of the skynet botnet and should be destroyed.

If your clock is flashing "0:00" or "12:00", you have no action to take to adapt to this change, lucky you.

If you haven't changed time in six months, congratulations, your clock will be accurate again!

In any case, you should still consider DST because it might affect some of your meeting schedules, particularly if you set up a new meeting schedule in the last 6 months and forgot to consider this change.

If your location does not have DST

Properly scheduled meetings affecting multiple time zones are set in UTC time, which does not change. So if your location does not observer time changes, your (local!) meeting time will not change.

But be aware that some other folks attending your meeting might have the DST bug and their meeting times will change.

Be kind to those poor souls which might be missing meetings by a full hour because time flies backwards for them.

If you do observe DST

If you are affected by daylight savings, your local meeting times will change for UTC meetings. Normally, your meeting times are scheduled to take this into account and the new hours should be reasonable.

But now is a good time to verify that. Take a look at your schedule for the next couple of weeks and reschedule meetings before the daylight saving come up to avoid too much disruption. You have only a couple of weeks to do so right now.

When do times change, how, and and where?

As regular readers will remember, the rule of thumb is:

Spring forward, fall backwards.

That is, during the season of Spring, the clocks move forward, and during the Fall (like right now), they move backwards. That is in the northern hemisphere, but then the southern hemisphere is often saner and doesn't switch anyways.

So time will move backwards which means an extra hour of sleep. Unless you have children or bad sleep, in which case your body doesn't care about what the clock says and will wake up one hour earlier than what it should.

And of course, this doesn't happen everywhere at once, so let's see when it happens where.

Europe

The dance starts in Europe.

The change happens on the last Sunday in October at 01:00 UTC (not local time!), that is October 25th. If you are in the central European timezone, also known as Amsterdam, Berlin, or Paris time depending on your national affiliation, that essentially means that at 2:59 local the clocks will fall back to 2:00 instead of going to 3:00.

Concretely, set your watch back one hour before going to bed, go to bed at the normal time, and enjoy an extra hour of sleep or leisure.

If you have kids, you might want to start getting them to bed slightly earlier every day for a week before the change so they take time getting used to the change. If you have trouble sleeping in the morning, find your inner child and do that to yourself as well.

USA / Canada

Then it's the US[1] and Canada[2] joining the dance, on the First Sunday in November at 02:00 local (not UTC!), that is, I believe, November 1st 2026.

This means that, at 1:59, the clocks will flip to 1:00, instead of 2:00.

Concretely, do like the Europeans and tweak your clock before going to bed.

That is a little less than four weeks from now.

[1] except Arizona (except the Navajo nation), US territories, and Hawaii

[2] except Yukon, Saskatchewan, (newly) British Columbia, (newly) Alberta, (newly) Northwest Territories, (newly) Manitoba, one island in Nunavut (Southampton Island), one town in Ontario (Atikokan) and small parts of Quebec (Le Golfe-du-Saint-Laurent)

Other places with DST

This time again, I must apologize to the people of Cuba, Lebanon, Israel, Palestine, Egypt, Chile, Australia, and New Zealand, as you fine folks all have your own DST rules that are omitted here for brevity. I rely on this page from Wikipedia to be updated by time nerds accurately for this message, and it should provide you with a rough idea of what's coming:

https://en.wikipedia.org/wiki/Daylight_saving_time_by_country

In general, changes also happen in October, but either on different times or different days, except in the south hemisphere, where they might happen in September (oops, sorry NZ folks, I'm late!).

Places without DST

Everyone else, enjoy, you're on the right side of history, and we thank you for the good example you give us.

Changes since last time

There's been lots of changes since last time:

This is my interpretation of the changes announced on the tzdata mailing list here:

https://lists.iana.org/hyperkitty/list/tz-announce@iana.org/latest

If the eastward trend continues, Canada should adopt country-wide "no daylight savings" rules by 2027, although there's actually no sign of the other provinces (Ontario, Québec and so on) currently running bills to change those rules just yet. Poor Canadians like me confused about time in their countries can refer to this section of Wikipedia for details:

https://en.wikipedia.org/wiki/Daylight_saving_time_in_Canada#By_province_and_territory

... and particularly the image featured there:

https://commons.wikimedia.org/wiki/File:Canada_time_zone_map-en.svg

It also seems like the US government might finally adopt a permanent daylight saving change bill in 2026, as the "Sunshine protection act" pass the house in July:

https://en.wikipedia.org/wiki/Sunshine_Protection_Act

True to form, this was associated with absolutely ridiculous pressure from Donald Trump against republicans (his own party!) objecting to the change:

On July 14, 2026, the House passed a Sunshine Protection Act bill backed by President Trump. Nevertheless, the bill was opposed in the Senate by Republicans, including Senator Cotton. In response, on October 3, 2026, Trump shared a post on Truth Social urging Cotton to approve the bill, where he revealed Cotton's personal cellphone number and called on people to call him.

https://www.theguardian.com/us-news/2026/oct/03/trump-tom-cotton-daylight-saving-time

Given that the last time the US did a major change to the daylight savings policy (in 2005), Canada followed suit to stay in sync, it's quite possible Trump's mad dash might actually finish getting rid of DST in North America:

https://en.wikipedia.org/wiki/Energy_Policy_Act_of_2005#Change_to_daylight_saving_time

October 08, 2026 07:30 PM UTC


Django Weblog

Django security reporting update

We are no longer accepting new security reports for the Django project through HackerOne. Existing reports submitted through HackerOne will remain open and continue to be handled by the Django Security Team.

If you discover a security issue in Django, please follow the reporting process described in the Django security policies.

Security issues should be reported by emailing security@djangoproject.com

October 08, 2026 11:00 AM UTC


Eli Bendersky

Monte-Carlo simulations

Monte Carlo simulations (or methods) is the technique of applying randomness and the Law of large numbers to the solution of various scientific and engineering problems. One of its first documented uses was by Stanislaw Ulam and John von Neumann for nuclear weapon simulations after WWII [1].

In this post I want to provide examples of some simple uses of Monte Carlo simulations. We'll start with the classical example of calculating the value of \pi by throwing darts.

Estimating pi

Suppose we take a square board and inscribe a quarter of a circle into it. We then proceed to throw darts at the board and record whether each dart hits inside or outside the quarter circle. Having thrown many such darts, we calculate the ratio of the darts inside the circle to the total number thrown.

Assuming our darts are distributed uniformly over the square, by the Law of large numbers this ratio should approach the ratio of areas of the quarter circle A_{circ} to the full square A_{square}.

With a square side length of 1, we have:

\[\frac{A_{circ}}{A_{square}}=\frac{\pi/4}{1}=\frac{\pi}{4}\]

Therefore:

\[\pi\approx 4\frac{\text{hits inside}}{\text{total throws}}\]

Here's a visualization:

A quarter circle of radius 1 inside a unit square.
101000

π ≈ —

Change the number of samples (dart throws) and click "Run" to regenerate. The code is very simple - here's a slightly sanitized version:

const total = Number(samples.value);
let inside = 0;
for (let i = 0; i < total; i++) {
  const x = Math.random();
  const y = Math.random();
  const inCircle = x * x + y * y <= 1;
  if (inCircle) inside++;
}
estimateValue = 4 * inside / total;

You'll notice that the estimate is relatively poor - even with 1000 samples - if you click "Run" several times, some numbers will be way off mark. While this method does estimate \pi, it's not a particularly good estimate. I find that running ~10 billion samples is necessary to estimate it to 4 digits after the decimal with reasonable reliability.

In general, for independent trials like these, the typical sampling error decreases in proportion to 1/\sqrt{N}, where N is the number of trials. This means that halving the error requires four times as many samples.

While the \pi estimation may seem whimsical, it's an example of an important class of problems to which Monte Carlo simulation is applied: numerical integration. Our simulation estimates the area under the quarter-circle curve, which is a definite integral.

Many integrals are very difficult to solve analytically, and much research has been done in the area of numerical analysis to develop methods to calculate integrals. Monte Carlo methods are particularly useful for high-dimensional integrals, where other numerical methods can become prohibitively expensive.

Combinatorial simulation - the game of SET

A common use of Monte Carlo methods is estimating complex combinatorial calculations. These often don't have analytical solutions, and enumerating all options is intractable due to the scale of the numbers involved. As an example, let's consider the game of SET. Each SET card has four attributes:

  1. Number of shapes (1, 2 or 3)
  2. Color (Red, Green or Purple)
  3. Shape type (Oval, Diamond or Squiggle)
  4. Shading (Empty, Striped or Solid)

And the goal is to find a "set" - three cards that are either all different or all the same for each attribute separately. As an example, here's a hand with a single set; see if you can find it [2]:

SET hand with a single set

And the next hand doesn't have any sets:

SET hand with no hands

Here's a question: given a freshly shuffled SET deck, what are the odds that the first 12 cards drawn will have no sets among them? This question is difficult to answer without using a computer.

It's easy to calculate the number of ways to deal a 12-card hand from a deck of 81:

\[\binom{81}{12}=70,724,320,184,700\]

But how many of these hands have no sets? Enumerating 70 trillion SET hands and checking each one can take quite a while, and there is no straightforward counting formula to answer this question. Some clever methods can be employed to leverage symmetries and other mathematical properties of SET to cut down this search space considerably. Donald Knuth himself worked on this problem and came up with a neat program (setset-all on his programs page) that found 2,284,535,476,080 such hands. Therefore, the answer to our question is:

\[\frac{2,284,535,476,080}{70,724,320,184,700}\approx 0.0323\]

There's a 3.23% chance that a randomly drawn hand of 12 cards from a full deck of SET will have no set in it.

Let's see how we can use a Monte Carlo simulation to answer this question with relatively small effort, without deep knowledge of the mathematical properties of SET that enable cutting down the search space Knuth-style. We can use the following pseudo-code:

C = 0
run N times:
  draw a random 12-card hand from a fresh deck
  count sets in the hand
  if no sets:
    C += 1

Estimated probability = C / N

After running 10 million simulated draws, I got an answer of 0.0323, which matches the real answer very closely.

The Monte Carlo approach lets us solve rather complicated problems in a very simple way. Suppose we want to answer the same question for a hand of 15 cards; this would blow up the search space considerably - there are about 100x more ways to select 15-card hands than there are to select 12-card hands. But for a Monte Carlo simulation, we adjust one small parameter and get a very reliable [3] answer (about 0.00037, in case you were wondering).

Retirement projection

One domain where Monte Carlo simulations are ubiquitous is projections for retirement portfolios. Suppose someone prepares to retire with a total sum of 1 million dollars in their portfolio; they'd like to be able to draw $30,000 a year from the portfolio for their living expenses. Would that work?

There's a large number of factors to take into account when analyzing this question, but for simplicity let's focus on just two: portfolio return and inflation. We can run a naive estimate, assuming average values: suppose an average yearly portfolio return of 4%, and average yearly inflation of 2% [4]

Let's denote our portfolio return as r=0.04, and inflation as q=0.02. Then the real return each year is:

\[r^{\mathrm{real}}=\frac{1+r}{1+q}-1\approx0.0196\]

Starting with $1,000,000, at the end of the year we'll have $1,019,600 and then draw $30,000 for living expenses [5], ending with $989,600. If we continue this way, the money runs out after ~55 years, which means that a person retiring at the age of 65 should be reasonably safe, right?

But this is very simplistic; assuming just average returns is risky, because they do a poor job of representing reality, and many factors have uncertainty. For example, the sequence of returns matters a lot; a bad year (-10%) followed by a great year (+18%) would still count as "4% on average" but produces significantly less money than two consecutive +4% years. Inflation is also unpredictable, and sometimes correlated with portfolio returns; there could be bad years of high inflation and low / volatile returns that can wreak havoc on a portfolio.

As we add factors (variance in yearly draws, mixed portfolios of stocks, bonds, real estate, life expectancy, unexpected events, changing tax laws etc.), relying on a single average estimate becomes increasingly more fraught. This is why Monte Carlo simulations are very popular in this domain: by drawing from reasonable distributions based on historical data, a Monte Carlo simulation can easily run a million different scenarios and provide estimates: for example, what are the odds of money running out before death.

Here's a useful chart from a simulation I ran:

Monte Carlo simulation of retirement, showing percentiles and odds of funds running out

In the top chart:

  • The dashed line shows the constant assumptions mentioned before: what happens when yearly return is always 4% and inflation is always 2%.
  • The shaded blue areas demonstrate the outcomes of 1,000,000 simulations where inflation and return numbers are drawn from reasonable normal distributions based on historical data. We see that in 25% of the cases, all money ran out by roughly 22 years.

In the bottom chart:

  • It's even easier to see how long the funds last; if we're interested in knowing, say, what are the odds that this plan will have enough money for 30 years - the chart shows it's about 60% (since in 40% of the simulations the funds were depleted at this point).

Looking a this simulation, under the current assumptions the plan sounds much riskier than the average assumption makes it appear. Assuming that a 65-y.o. person would plan for 25 years of retirement until death, the ~30% odds of not having sufficient funds for this duration of time are sobering. Perhaps a change in plans is needed (such as a more frugal lifestyle or securing additional funds in some way).

Retirement projection is only one of may ways in which Monte Carlo simulations are used for financial and economical applications; given the high uncertainty of these domains, it's very difficult to plan using analytical calculations. Company sales projections, growth projections, stock offering prices and much more uses Monte Carlo simulations to arrive at estimates with reasonable error bars.

Code

All the code for the explorations in this post is available on GitHub.


[1]While these techniques were conceptually understood much earlier, it's not surprising that their first real applications coincided with the development of the first digital computers. As we'll see later in the post, Monte Carlo simulations benefit from running large numbers of trials to get reasonable accuracy.
[2]The answer is: three empty red diamonds, three solid purple ovals, three striped green squiggles. Note that for each of the 4 SET attributes, these three cards are either all the same or all different.
[3]For the same number of trials, this estimate has greater relative uncertainty than the 12-card estimate, because we encounter far fewer hands without a set.
[4]For the examples in this post, we'll be using real dollars, or today's value of the money. We'll assume that the $30,000 yearly draw doesn't change and will instead apply inflation to the portfolio itself.
[5]More sophisticated simulations would let us control these parameters; for example, are the expense funds drawn at the beginning or end of each year, or distributed on a monthly basis?

October 08, 2026 09:35 AM UTC