Structural Pattern Matching in Python I

In this blog, which is a first of a three-part series, we talk about the structural pattern-matching support in Python.

GraphQL has a role beyond API Query Language- being the backbone of application Integration
background Coditation

Structural Pattern Matching in Python I

Python 3.10 introduced structural pattern-matching syntax in python. Typically used in functional programming languages such as Haskell, rust and hybrid programming languages such as scala, more and more object-oriented programming languages are adopting spm syntax as a core feature.

We start with basic definitions, types of pattern-matching, and basic pattern matching examples in this blog & move to pattern matching examples in the second part, and finally discuss class pattern in the third part.

What is structural pattern matching?

Structural pattern matching is a feature in some programming languages that allows you to compare objects based on their structure rather than just their type. This can be useful when you want to compare objects that may have different types but have the same underlying structure.
The specific syntax for structural pattern matching varies depending on the programming language. In some languages, it is implemented using a keyword such as match or a case, while in others it is implemented using the instanceof operator in combination with special syntax for specifying patterns.
Structural pattern matching can make your code more expressive and easier to read, as it allows you to directly compare the structure of objects without having to write long and complex type-checking code. It is available in languages such as Scala, Rust, Java (as of version 14), Python (as of version 3.10)
In python, a pattern is a value defined after the case keyword which acts as a minimal structural constraint against which a subject is matched.
In some cases, it also helps us bind the subject partly or fully to a free variable.

What are the different types of pattern matching in python?

There are 9 different types of patterns

  • Literal Pattern
  • Capture Pattern
  • Wildcard Pattern
  • AS Pattern
  • OR Pattern
  • Guard Pattern
  • Value Pattern
  • Sequence Pattern
  • Mapping Pattern
  • Class Pattern

Literal pattern matching

This includes matching literals in python including number, string, None, True, False, etc.
Let us understand with an example



def literal_patterns(subject):

    match subject:
        case 1:
            print("The subject matches with 1")
        case 1.0:
            print("The subject matches with 1.0")
        case 2+3j:
            print(f"The real and imaginary parts are 2 and 3 respectively.")
        case "Masashi Kishimoto":
            print(f"Masashi Kishimoto is the author of manga series which was first published in 1999.")
        case None:
            print("The subject matches with None")
        case True:
            print("The subject matches with True")
            

Here is the output in different cases of subject



    subject = 1 # Output: The subject matches with 1
    subject = 1.0 # Output: The subject matches with 1
    subject = 'Masashi Kishimoto' # Output: Masashi Kishimoto is the author of manga series which was first published in 1999.
    subject = None # Output: The subject matches with None
    subject = True # Output: The subject matches with 1
    subject = 2+3j # Output: The real and imaginary parts are 2 and 3 respectively.
    

In the above example, the case for 1.0 or True will not be called even if the value for a subject is 1.0 or True respectively.
Instead, the case for 1 will be used, As for literal pattern matching == or __eq__ is used.

Similarly, 0 will be a match for the subject value False.
F-strings are not allowed to be used as patterns or cases.

Capture pattern matching

These are patterns where we can assign a subject(partially or fully) to a free variable.



def capture_patterns(subject):

    match subject:
        case [a,]:
            print(f"Collection has only one entry: {a}")
        case (a, b):
            print(f"Find flowrate for volume {a}litres and time {b}secs")
        case value:
            print(f"{value} is the value of subject")
            

Here are the different types of outputs



    subject = (22,) # Output: Collection has only one entry: 22
    subject = [33, 44] # Output: Find flowrate for volume 33litres and time 44secs
    subject = 87 # Output: 87 is the value of the subject
    

  1. A free variable can be used only once for a single pattern - In the above example a can be seen in two patterns but its usage in each pattern is only once.
  2. An Irrefutable pattern in the above example value can only be used as the last pattern to be matched.
  3. The free variables a or b can be used outside the match scope while using an Irrefutable pattern value will result in UnboundLocalError: local variable 'value' referenced before assignment error
  4. Unless a class pattern is explicitly mentioned the list and tuple can be matched Ex: subject case match (22,66) [a,b] matched [22,66] (a,b) matched (22,) [a,] matched [22,] (a,) matched

Wildcard patterns

These patterns use single underscore _ to match a part of or whole subject.



def wildcard_patterns(subject):

    match subject:
        case (1,_,1):
            print(f"{subject} is a palindrome collection")
        case (_,_):
            print(f"{subject} is a collection of 2")
        case _:
            print("Unknown Match")
            

Here are the different outputs



    subject = (1,2) # Output: (1,2) is a collection of 2
    subject = (1,2,1) # Output: (1,2,1) is a palindrome collection
    subject = (1,2,3) # Output: Unknown Match
    

The wildcard pattern can be used when part of the subject matched to the wildcard is not explicitly used as in the case of the capture pattern.

AS patterns

This pattern is used to bind the free variable(name) on the right side of as to the subject matched with the pattern on its left side.



def as_patterns(subject):

    match subject:
        case "Kg" as mass:
            print(f"SI unit for mass is {mass}")
        case "N" as a force:
            print(f"SI unit for force is {force}")
            

Here are the different outputs



    subject = "Kg" # Output: SI unit for mass is Kg
    subject = "N" # Output: SI unit for force is N
    

The _(wildcard) cannot be used on the right side of as, as it can’t be reused. In case it’s used on the right side of as it will result in a syntax error. (SyntaxError: cannot use _ as a target).

OR patterns

This pattern works similarly to a or keyword but uses pipe | to do so.



def or_patterns(subject):

    match subject:
        case "RED" | "YELLOW" | "BLUE" as p_colour:
            print(f"{p_colour} is one of the primary colours") 
        case colour:
            print(f"{colour} is not one of the primary colours")
            

Here are the different outputs



    subject = "RED" # Output: RED is one of the primary colours
    subject = "GREEN" # Output: GREEN is not one of the primary colours
    

Guard

A guard is a if condition on top of patterns.



def guard(subject):

    match subject:
        case int(number) if number % 2:
            print(f"{number} is an odd integer")
        case int(number):
            print(f"{number} is an even integer")  
        case element:
            print(f"{element} is not an integer")
            

Here are the different outputs



    subject = 33 # Output: 33 is an odd integer
    subject = 34 # Output: 34 is an even integer
    

Its important to know that a guard condition is only checked if an initial pattern is matched.

In this part one of three parts series of structural pattern matching in python, we discussed the definition and basic pattern matching in python 3.10.
In the next blog, we will discuss Value Patterns, Sequence Patterns, and Mapping Patterns.

Hi, I am Harris Hujare. As a software developer, I design and implement scalable and maintainable systems. I have a passion for learning new technologies and creating software utilities making lives easier.

Want to receive update about our upcoming podcast?

Thanks for joining our newsletter.
Oops! Something went wrong.

Latest Articles

Designing multi-agent systems using LangGraph for collaborative problem-solving

Learn how to build sophisticated multi-agent systems using LangGraph for collaborative problem-solving. This comprehensive guide covers the implementation of a software development team of AI agents, including task breakdown, code implementation, and review processes. Discover practical patterns for state management, agent communication, error handling, and system monitoring. With real-world examples and code implementations, you'll understand how to orchestrate multiple AI agents to tackle complex problems effectively. Perfect for developers looking to create robust, production-grade multi-agent systems that can handle iterative development workflows and maintain reliable state management.

time
7
 min read

Designing event-driven microservices architectures using Apache Kafka and Kafka Streams

Dive into the world of event-driven microservices architecture with Apache Kafka and Kafka Streams. This comprehensive guide explores core concepts, implementation patterns, and best practices for building scalable distributed systems. Learn how to design event schemas, process streams effectively, and handle failures gracefully. With practical Java code examples and real-world architectural patterns, discover how companies like Netflix and LinkedIn process billions of events daily. Whether you're new to event-driven architecture or looking to optimize your existing system, this guide provides valuable insights into building robust, loosely coupled microservices.

time
12
 min read

Implementing Custom Instrumentation for Application Performance Monitoring (APM) Using OpenTelemetry

Application Performance Monitoring (APM) has become crucial for businesses to ensure optimal software performance and user experience. As applications grow more complex and distributed, the need for comprehensive monitoring solutions has never been greater. OpenTelemetry has emerged as a powerful, vendor-neutral framework for instrumenting, generating, collecting, and exporting telemetry data. This article explores how to implement custom instrumentation using OpenTelemetry for effective APM.

Mobile Engineering
time
5
 min read