Switch-Case Statements in Python 3.10 | Towards Data Science

Python 3.10 is beginning to fill-out with plenty of fascinating new features. One of those, in particular, caught my attention — structural pattern matching — or as most of us will know it, switch/case statements.
Switch-statements have been absent from Python despite being a common feature of most languages.
Back in 2006, PEP 3103 was raised, recommending the implementation of a switch-case statement. However, after a poll at PyCon 2007 received no support for the feature, the Python devs dropped it.
Fast-forward to 2020, and Guido van Rossum, the creator of Python, committed the first documentation showing the new switch-statements, which have been named Structural Pattern Matching, as found in PEP 634.
What we have here is much more than a simple switch-case statement, however (hence match-case), as we will see soon.
Let’s take a look at how this new logic works.
> Structural Pattern Matching  - Intro  - Another Example  - Real Use-Case With JSON
The pattern matching takes a value following match and allows us to write out several potential cases, each defined by case. Where we find a match between the match-case we will execute the respective code.
For example:
http_code = "418"match http_code:    case "200":        print("OK")        do_something_good()    case "404":        print("Not Found")        do_something_bad()    case "418":        print("I'm a teapot")        make_coffee()    case _:        print("Code not found")
Here we’re checking multiple conditions and performing different operations based on what value we’re finding inside http_code.
Immediately it’s evident that yes, we can build the same logic using a chunk of if-elif-else statements:
http_code = "418"if http_code == "418":    print("OK")    do_something_good()elif http_code == "404":    print("Not Found")    do_something_bad()elif http_code == "418"    print("I'm a teapot")    make_coffee()else:    print("Code not found")
However, by using the match-case statement we remove the repetition of http_code ==Which can look much cleaner when testing for many different conditions.
We can find some great examples of using the match-case statement to improve code readability in PEP 635. One of those is this example showing us how to use match-case to check the type and structure of our subject:
match x:    case host, port:        mode = "http"    case host, port, mode:        pass
Here we expect to receive connection details in a tuple format and assign the given values to the correct variables.
In this case, if the connection mode is not defined within the tuple (e.g., only two values have been provided — the host and port), we assume that the connection mode is “http”.
However, in other cases, we may expect that the mode is explicitly defined. So rather we might receive a tuple like (<host>, <port>, "ftp") — in which case we would not want to set mode to “http”.
Now, if we wanted to write this same logic using an if-else statement, we would get this:
if isinstance(x, tuple) and len(x) == 2:    host, port = x    mode = "http"elif isinstance(x, tuple) and len(x) == 3:    host, port, mode = x
Which option is preferred may vary, but for me, the match-case implementation looks much cleaner.
Another use-case that looks interesting is the ability to parse dictionary objects differently based on their structure. A great test use-case of this is parsing the SQuAD 2 dataset.
The SQuAD 2 dataset is an incredibly popular set of question-answer pairs used for training machine-learning models for question-answering. We can download the data with:
import requests
import json

url = 'https://rajpurkar.github.io/SQuAD-explorer/dataset/'
file = 'train-v2.0.json'

res = requests.get(f'{url}{file}')
# write to file
with open(file, 'wb') as f:
    for chunk in res.iter_content(chunk_size=4):
        f.write(chunk)

If we take a look at the structure of SQuAD, there are clearly a few levels to it, which we’ll need to consider when parsing:
The problem that we have is that not all samples use the same dictionary format.
If we look at the last few samples we will see that the qas list contains both answers and plausible_answers — whereas the earlier samples contained just answers:
Let’s try applying the new match-case statements to build a cleaner alternative to the heavy if-else logic required to deal with this. First, we load the data:
The SQuAD JSON contains multiple layers. After accessing squad['data'] we need to iterate through each group of questions, then through each paragraph, then through each qas (question-answers) — this looks like:
And this is where things get interesting. Using if-else logic, we get something like this:
new_squad = []

for group in squad['data']:
    for paragraph in group['paragraphs']:
        for qa in paragraph['qas']:
            question = qa['question']
            if 'answers' in qa.keys() and len(qa['answers']) > 0:
                answers = qa['answers'][0]['text']
            elif 'plausible_answers' in qa.keys() and len(qa['plausible_answers']) > 0:
                answers = qa['plausible_answers'][0]['text']
            else:
                answers = None
            new_squad.append((question, answers))

new_squad[:5], new_squad[-5:]

([('When did Beyonce start becoming popular?', 'in the late 1990s'),
  ('What areas did Beyonce compete in when she was growing up?',
   'singing and dancing'),
  ("When did Beyonce leave Destiny's Child and become a solo singer?", '2003'),
  ('In what city and state did Beyonce  grow up? ', 'Houston, Texas'),
  ('In which decade did Beyonce become famous?', 'late 1990s')],
 [('Physics has broadly agreed on the definition of what?', 'matter'),
  ('Who coined the term partonic matter?', 'Alfvén'),
  ('What is another name for anti-matter?', 'Gk. common matter'),
  ('Matter usually does not need to be used in conjunction with what?',
   'a specifying modifier'),
  ('What field of study has a variety of unusual contexts?', 'physics')])
It’s not beautiful, but it works. Now let’s rewrite this with some match-case logic:
It definitely looks a lot less busy and is a pretty cool alternative to the original version of the parsing logic.
That’s all for this quick look at the new structural pattern matching being introduced to Python 3.10! The full release is expected in early October 2021.
Personally, I think this new syntax looks really good — although I’m 50/50 on it at the moment. Once more users begin coding with match-case, I’m confident that the community will quickly establish a consensus and best-practices.
But for now, it looks cool — I’m excited!
I hope you’ve enjoyed the article. Let me know if you have any questions or suggestions via Twitter or in the comments below! If you’re interested in more content like this, I post on YouTube too.
Thanks for reading!
If you’re interested in reading about a few of the other new features coming with Python 3.10, check out my other article covering a few of the best:
towardsdatascience.com
🤖 70% Discount on the NLP With Transformers Course