789

Is there a Python equivalent for the switch statement?

llRub3Nll
  • 53
  • 1
  • 10
John Alley
  • 8,067
  • 3
  • 14
  • 10
  • 43
    As of Python 3.10 you can use Python's `match ... case` syntax: [PEP 636](https://www.python.org/dev/peps/pep-0636/). – iacob Mar 27 '21 at 09:50
  • 34
    **Python 3.10.0 provides an official syntactic equivalent, making the submitted answers not the optimal solutions anymore!** In [this SO post](https://stackoverflow.com/a/66877137/6685358) I try to cover everything you might want to know about the `match`-`case` construct, including **common pitfalls** if you're coming from other languages. Of course, if you're not using Python 3.10.0 yet, the existing answers apply and are still valid for 2021. – fameman Apr 02 '21 at 16:07
  • 3
    I would've written this in an answer to this post, but unfortunately it doesn't allow for any more answers. But with more than one million views, I think this question needs at least a redirection to a more modern answer - especially when 3.10.0 becomes stable and Python beginners come across this post. – fameman Apr 02 '21 at 16:07

2 Answers2

1037

Python 3.10 and above

In Python 3.10, they introduced the pattern matching.

Example from the Python documentation:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"

        # If an exact match is not confirmed, this last case will be used if provided
        case _:
            return "Something's wrong with the internet"

Before Python 3.10

While the official documentation are happy not to provide switch, I have seen a solution using dictionaries.

For example:

# define the function blocks
def zero():
    print "You typed zero.\n"

def sqr():
    print "n is a perfect square\n"

def even():
    print "n is an even number\n"

def prime():
    print "n is a prime number\n"

# map the inputs to the function blocks
options = {0 : zero,
           1 : sqr,
           4 : sqr,
           9 : sqr,
           2 : even,
           3 : prime,
           5 : prime,
           7 : prime,
}

Then the equivalent switch block is invoked:

options[num]()

This begins to fall apart if you heavily depend on fall through.

Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
Prashant Kumar
  • 20,069
  • 14
  • 47
  • 63
  • 44
    The dictionary must come after the function definitions – flexxxit Feb 27 '14 at 12:50
  • 17
    Regarding fall-through, couldn't you use `options.get(num, default)()`, or am I misunderstanding? – Zaz Sep 24 '15 at 00:24
  • 6
    I think i meant more for the case where a label executes some code, and then continues into a block for another label. – Prashant Kumar Sep 24 '15 at 00:32
  • Sorry for the late response - for the sake of brevity, couldn't you organize the dictionary as: `options = { 0: "print("You typed zero.\n")", 1: "print("You typed one.\n")", } ` Then `eval` the dictionary value? Is there a reason this isn't "proper"? –  Jun 13 '16 at 17:09
  • 1
    For static functions use: options[num].__func__() – Stephan Schielke Apr 08 '17 at 15:19
  • 8
    @IanMobbs It's almost **NEVER** "proper" to put code in a constant string in quotes then `eval` it. 1) code doesn't get checked by your editor for validity. 2) it doesn't get optimised to bytecode at compilation. 3) you can't see syntax highlighting. 4) fiddly if you have multiple quotes - indeed your comment needs escaping! If you want brevity, you can use a `lambda` instead, though I think that's considered un-pythonic. – Sanjay Manohar Jul 26 '17 at 14:26
  • This can also be used to switch between values like integers. Example: `types = { 0 : 4, 1 : 2, 2 : 9, 3 : 8, } return types[val]`. When `val` is 2, your function will return 9 in my example. – Melroy van den Berg Aug 12 '17 at 20:17
  • 107
    as an aside, 2 is a prime number – 333kenshin Sep 05 '17 at 21:16
  • 2
    Because of all the function definitions and invocations, it might come cheaper to just use `if` and `elif` statements. – Bachsau Apr 18 '18 at 16:55
  • 3
    Actually,building a dictionary where the values are functions to be used to replace a "switch...case" will be overkill, and over-complicated in almost all cases. The correct replacement is `if/elif/else` as stated in @Lennardregebro's answer. That should be a no-brainer. – jsbueno Apr 17 '20 at 21:07
  • 1
    I don't like this solution, switch allows write code if a condition matches, in this example how could we define parameters to this function?? also why do we need to call a function ? I could return value inside the switch/case – dave008 May 08 '20 at 21:16
  • 1
    For some reason, the syntax in the beginning, the one with the `match`, isn't working with me on python 3.8. – steoiatsl Nov 27 '21 at 01:08
  • Might have confused `3.10` for `3.1` back then or something. Thanks. @JonnyHenly – steoiatsl Jun 14 '22 at 04:25
  • 3
    how in this universe did it take a language 30 years to implement this??? – java-addict301 Jan 25 '23 at 02:41
  • functions parameter are easier to handle with if/elif/else approach – Greg7000 Jun 15 '23 at 13:30
268

The direct replacement is if/elif/else.

However, in many cases there are better ways to do it in Python. See "Replacements for switch statement in Python?".

Community
  • 1
  • 1
Lennart Regebro
  • 167,292
  • 41
  • 224
  • 251