skip to navigation
skip to content

Planet Python

Last update: January 09, 2026 04:46 AM UTC

January 08, 2026


Rodrigo Girão Serrão

Recursive structural pattern matching

Learn how to use structural pattern matching (the match statement) to work recursively through tree-like structures.

In this short article you will learn to use structural pattern matching in recursive, tree-like data structures.

The examples from this article are taken from a couple of recent issues of my weekly newsletter.

A recursive data structure

Structural pattern matching excels at... matching the structure of your objects! For the two examples in this article, we'll be using a number of dataclasses that you can use to build abstract Boolean expressions:

from dataclasses import dataclass

class Expr:
    pass

@dataclass
class And(Expr):
    exprs: list[Expr]

@dataclass
class Or(Expr):
    exprs: list[Expr]

@dataclass
class Not(Expr):
    expr: Expr

@dataclass
class Var(Expr):
    name: str

For example, the code Not(And([Var("A"), Var("B")])) represents the Boolean expression not (A and B).

Evaluating a Boolean expression

Suppose you have a Boolean expression built out of the components shared above. How do you evaluate that formula if you are given the assignments that map the variables to their values?

For example, if you have the assignments {"A": True, "B": False} (for example, a dictionary that maps variable names to values), how can you determine that the expression Not(And([Var("A"), Var("B")])) is True?

This is where structural pattern matching can be applied recursively and it's where it really shines!

To solve this problem, you will write a function called evaluate(expression: Expr, assignments: dict[str, bool]) -> bool. Your function accepts an expression and the assignments in the form of a dictionary and it returns the final Boolean value the expression evaluates to.

Since you're accepting an expression, you're going to use the match statement on the full expression and then create a case branch for each of the possible expressions you might have:

  1. a variable;
  2. an And expression;
  3. an Or expression; or
  4. a Not expression.

The structure of the code looks like this:

def evaluate(expression: Expr, assignments: dict[str, bool]) -> bool:
    match expression:
        case Var(): pass
        case And(): pass
        case Or(): pass
        case Not(): pass

The trick here is realising that you're using Expr as the type of the argument but really, you always expect the argument to be an instance of one of the subclasses of Expr, and not a direct Expr instance.

However, to make sure you don't trip on a weird bug later on, and because this matching is supposed to be exhaustive – you're supposed to have one case for each subclass of Expr – you can defend yourself by including a catch-all pattern that raises an error.

When I'm being lazy, I just raise a RuntimeError:

def evaluate(expression: Expr, assignments: dict[str, bool]) -> bool:
    match expression:
        case Var(): pass
        case And(): pass
        case Or(): pass
        case Not(): pass
        case _:
            raise RuntimeError(
                f"Couldn't evaluate expression of type {type(expression)}."
            )

Now, it's just a matter of implementing the evaluation logic. In the case of a variable, all you have to do is fetch the variable value from the corresponding dictionary. However, to make it more convenient to...

January 08, 2026 03:22 PM UTC


Stéphane Wirtel

Automating TLS Certificate Monitoring with GitHub Actions, certificate_watcher, and Slack

Introduction

As a consultant constantly working with clients, I found myself in a familiar predicament: my head was always down, focused on delivering value to customers, but my own infrastructure monitoring was non-existent. I had no simple way to track SSL/TLS certificate expirations across the multiple domains I managed - personal sites, client projects, and community services.

I needed a solution, but I had several constraints:

  1. No time for complex setup: I couldn’t afford to spend days installing, configuring, and deploying yet another monitoring service
  2. Easy maintenance: Whatever I built had to be low-maintenance - I didn’t want another system to babysit
  3. Transparency and control: I wanted a simple text file in Git listing the hosts to monitor, so I could see exactly what was being checked and track changes over time
  4. Zero infrastructure: No servers to provision, patch, or pay for

Around this time, a friend named Julien shared his project called certificate_watcher, a lightweight Python tool for checking SSL certificate expiration. I contributed a few patches (if memory serves), and it clicked: what if I could combine this with GitHub Actions and Slack notifications?

January 08, 2026 12:00 AM UTC

January 07, 2026


Real Python

How to Build a Personal Python Learning Roadmap

Learn how to create a personalized Python learning roadmap. Set goals, choose resources, and build a plan to track your progress and stay motivated.

January 07, 2026 02:00 PM UTC


Stéphane Wirtel

dsmtpd 1.2.0: Test Your Emails Risk-Free

The Test Email That Never Should Have Been Sent

You know that feeling? You’re developing a new email feature, you run your test script, and boom — you realize 3 seconds too late that you used the production database. Your CEO just received an email with the subject “TEST - DO NOT READ - LOREM IPSUM”.

Or worse: you configured a cloud SMTP server for testing, forgot to disable actual sending, and now your Mailgun account is suspended for “suspicious activity” because you sent 847 emails to test@example.com in 5 minutes.

January 07, 2026 12:00 AM UTC


Python⇒Speed

Unit testing your code's performance, part 1: Big-O scaling

January 07, 2026 12:00 AM UTC

January 06, 2026


PyCoder’s Weekly

Issue #716: Performance Numbers, async Web Apps, uv Speed, and More (Jan. 6, 2026)

January 06, 2026 07:30 PM UTC


Django Weblog

Django bugfix releases issued: 5.2.10, 6.0.1

Today we've issued the 5.2.10 and 6.0.1 bugfix releases.

The release packages and checksums are available from our downloads page, as well as from the Python Package Index.

The PGP key ID used for these releases is Jacob Walls: 131403F4D16D8DC7

January 06, 2026 06:00 PM UTC


Real Python

Tips for Using the AI Coding Editor Cursor

Learn Cursor fast: AI-powered coding with agents, project-aware chat, inline edits, and VS Code workflow -- ship smarter, sooner.

January 06, 2026 02:00 PM UTC


Seth Michael Larson

“Food JPEGs” in Super Smash Bros & Kirby Air Riders

January 06, 2026 12:00 AM UTC

January 05, 2026


PyCharm

The next edit suggestions feature is now enabled in all JetBrains IDEs for JetBrains AI Pro, AI Ultimate, and AI Enterprise subscribers. Yes, you read that right! JetBrains-native diff suggestions are available right in your editor. Global support for optimized latency. Out-of-the-box IDE actions for reliability. And the best part? It doesn’t consume your AI […]

January 05, 2026 07:41 PM UTC


Real Python

Learn From 2025's Most Popular Python Tutorials and Courses

Pick from the best Python tutorials and courses of 2025. Revisit core skills, 3.14 updates, AI coding tools, and project walkthroughs. Kickstart your 2026!

January 05, 2026 02:00 PM UTC

Quiz: How to Convert Bytes to Strings in Python

Decode bytes into readable strings in Python. Test your skills working with data from files, APIs, and databases.

January 05, 2026 12:00 PM UTC

Quiz: How to Properly Indent Python Code

Practice proper Python indentation. Take a quiz on using spaces, editor settings, and autoformatting correctly.

January 05, 2026 12:00 PM UTC


Patrick Müller

Static Protocols in Python: Behaviour Over Inheritance

The first time I read about protocols was in the book "Fluent Python" by Luciano Ramalho. This book goes deep. Deeper than I knew Python at that time. If you hadn&apost heard of Protocols before, I&aposll give you a short introduction.

Protocols have something

January 05, 2026 09:23 AM UTC


Talk Python to Me

#533: Web Frameworks in Prod by Their Creators

Today on Talk Python, the creators behind FastAPI, Flask, Django, Quart, and Litestar get practical about running apps based on their framework in production. Deployment patterns, async gotchas, servers, scaling, and the stuff you only learn at 2 a.m. when the pager goes off. For Django, we have Carlton Gibson and Jeff Triplet. For Flask, we have David Lord and Phil Jones, and on team Litestar we have Janek Nouvertné and Cody Fincher, and finally Sebastián Ramírez from FastAPI is here. Let’s jump in.

January 05, 2026 08:00 AM UTC


Python Bytes

#464 Malicious Package? No Build For You!

Topics include ty: An extremely fast Python type checker and LSP, Python Supply Chain Security Made Easy, typing_extensions, and MI6 chief: We'll be as fluent in Python as we are in Russian.

January 05, 2026 08:00 AM UTC


Glyph Lefkowitz

How To Argue With Me About AI, If You Must

If you insist we have a conversation, please come prepared.

January 05, 2026 05:22 AM UTC


Zato Blog

Python scheduler for API integrations

Python scheduler for API integrations

Are you looking for a practical way to automate API tasks with reliable scheduling? This tutorial demonstrates how to implement task scheduling using Zato within Docker.

The guide focuses on real-world implementation rather than theory, showing you how to build scheduling solutions that work consistently in production environments.

What you'll learn in the tutorial:


Python Scheduler

More resources

➤ Python API integration tutorials
What is an integration platform?
Python Integration platform as a Service (iPaaS)
What is an Enterprise Service Bus (ESB)? What is SOA?
Open-source iPaaS in Python
What is a Network Packet Broker? How to automate networks in Python?

January 05, 2026 03:00 AM UTC

January 04, 2026


Python Morsels

Debugging with f-strings

If you're debugging Python code with print calls, consider using f-strings with self-documenting expressions to make your debugging a little bit easier.

Table of contents

  1. A broken Python program
  2. Troubleshooting with print
  3. Using self-documenting expressions
  4. Self-documenting expressions work with any expression
  5. Using format specifiers with self-documenting expressions
  6. Making more readable self-documenting expressions
  7. Summary

A broken Python program

Here we have a program that makes a random math prompt and then validates whether the answer give by the user is correct:

import random

x = random.randrange(1, 10)
y = random.randrange(1, 10)

answer = input(f"What's {x} multiplied by {y}? ")
expected = x * y

if answer == expected:
    print("Correct!")
else:
    print("That's incorrect")

This program doesn't work right now:

$ python3 check_mult.py
What's 9 multiplied by 8? 72
That's incorrect

Our program always tells us that our answer is incorrect.

Troubleshooting with print

Now, we could try to …

Read the full article: https://www.pythonmorsels.com/debugging-with-f-strings/

January 04, 2026 05:51 PM UTC


Artem Golubin

Recent optimizations in Python's Reference Counting

It's been a while since I've written about CPython internals and its optimizations. My last article on garbage collection was written 8 years ago.

A lot of small optimizations were added since then. In this article, I will highlight a new optimization for reference counting that uses a static lifetime analysis.

Background on reference counting in CPython

Reference counting is the primary memory management technique used in CPython.

In short, every Python object (the actual value behind a variable) has a reference counter field that tracks how many references point to it. When an object's reference count drops to zero, the memory occupied by that object is immediately deallocated.

For hot loops, this can lead to significant overhead due to the frequent incrementing and decrementing of reference counts.[....]

January 04, 2026 05:14 PM UTC


EuroPython

Humans of EuroPython: Marina Moro López

EuroPython wouldn’t exist if it weren’t for all the volunteers who put in countless hours to organize it. Whether it’s contracting the venue, selecting and confirming talks & workshops or coordinating with speakers, hundreds of hours of loving work have been put into making

January 04, 2026 02:26 AM UTC

January 03, 2026


Hugo van Kemenade

Localising xkcd

I gave a lightning talk at a bunch of conferences in 2025 about some of the exciting new things coming in Python 3.14, including template strings.

One thing we can use t-strings for is to prevent SQL injection. The user gives you an untrusted t-string, and you can sanitise it, before using it in a safer way.

I illustrated this with xkcd 327, titled “Exploits of a Mom”, but commonly known as “Little Bobby Tables”.

I localised most of the slides for the PyCon I was at, including this comic. Here they are!

PyCon Italia #

May, Bologna

Did you really name your son Roberto’); DROP TABLE Students;– ? Oh, yes. Piccolo Berto Tables, we call him.

PyCon Greece #

August, Athens

Did you really name your son Κωνσταντίνος’); DROP TABLE Students;– ? Oh, yes. Μικρός Ντίνος Tables, we call him.

PyCon Estonia #

October, Tallinn

Did you really name your son Raivo’); DROP TABLE Students;– ? Oh, yes. Pisikene Tables, we call him.

PyCon Finland #

October, Jyväskylä

Did you really name your son Juhani’); DROP TABLE Students;– ? Oh, yes. Pikku Jussi, we call him.

PyCon Sweden #

October, Stockholm

Did you really name your son Oskar’); DROP TABLE Students;– ? Oh, yes. Lille Ogge Bord, we call him.

Thanks #

Thanks to Randall Munroe for licensing the comic under the Creative Commons Attribution-NonCommercial 2.5 License. These adaptations are therefore licensed the same way.

Finally, here’s links for 2026, I recommend them all:

January 03, 2026 02:06 PM UTC

January 02, 2026


Real Python

The Real Python Podcast – Episode #278: PyCoder's Weekly 2025 Top Articles & Hidden Gems

PyCoder's Weekly included over 1,500 links to articles, blog posts, tutorials, and projects in 2025. Christopher Trudeau is back on the show this week to help wrap up everything by sharing some highlights and uncovering a few hidden gems from the pile.

January 02, 2026 12:00 PM UTC


Glyph Lefkowitz

The Next Thing Will Not Be Big

Disruption, too, will be disrupted.

January 02, 2026 01:59 AM UTC


Seth Michael Larson

New ROM dumping tool for SNES & Super Famicom from Epilogue

January 02, 2026 12:00 AM UTC