Python Will Soon Support Switch Statements

Rejoice! Gone are the long chains of ifelse statements, because switch statements will soon be here — sort of. What the Python gods are actually giving us are match statements. match statements are awfully similar to switch statements, but have a few really cool and unique features, which I’ll attempt to illustrate below.

Flip The Switch

A switch statement is often used in place of an ifelse ladder. Here’s a quick example of the same logic in C, first executed with an if statement, and then with a switch statement:

Essentially, a switch statement takes a variable and tests it for equality against a number of different cases. If none of the cases match, then the default case is invoked. Notice in the example that each case is terminated by a break. This protects against more than one case matching (or allows for cascading), as the cases are checked in the order in which they are listed. Once a case is completed, break is called and the switch statement exits.

A Match Made In Heaven

You can think of match statements as “Switch 2.0”. Before we get into the nitty-gritty here, if all you want is switch in Python then you’re in luck, because they can be used in the same way. Here’s a similar example to what we looked at earlier, this time using match in Python.

There are a few differences to note right off the bat. First, there are no break statements. The developers were concerned about confusion if a break statement were called inside a match statement inside a loop — what breaks then, the loop or the match? Here, the first case that is satisfied is executed, and the statement returns. You’ll also notice that rather than default, we have case _, which behaves in the same way.

The Power of Pattern Matching

So, we’ve got a switch statement with slightly different syntax, right? Not quite. The name match was used for a reason — what’s actually going on here is something called Pattern Matching. To illustrate what that is, let’s look at a more exciting example, right out of the feature proposal to add the keyword in question to Python:

Wow! We just took an object, checked its type, checked it’s shape, and instantiated a new object without any indexing, or even a len() call. It also works on any type, unlike the classic switch which only works on integral values. In case this wasn’t cool enough for you, patterns can be combined. Again, from the feature proposal:

Okay, okay — one more example. This is where the match statement gets really powerful. Patterns themselves can include comparisons, known as guards. This lets you filter values within each case statement:

Sold! When Can I Try?

We’ll get our hands on this magical new command in Python 3.10, slated for a full release on October 4th, 2021. For the adventurous, an alpha version (Python 3.10.0a6) is available for download today. It might be worth spending some time getting acquainted with the pattern matching, like understanding the difference between matching literal values and matching variables.

So why doesn’t every language have match statements? They’re clearly better than switch statements!
That’s what I said at least, and my girlfriend Sara was quick to raise her eyebrows and explain that there’s a huge performance overhead involved. The switch statement in C is relatively simple. It compares integers to one another, executing n constant-time operations. All of the power and convenience that comes with the match statement means a lot is going on in the background, which in turn slows down the code execution — an incredibly Pythonic tradeoff to make.

I find an efficiency hit a small price to pay for such expanded functionality, but as a Mechanical Engineer my favorite languages are Matlab and Python so you probably should take my opinion here with a grain of salt.

113 thoughts on “Python Will Soon Support Switch Statements

      1. I write C switches to fall through, sometimes, but feel the need to comment it:

        // fall through
        case 2:

        So I would suggest that the C version is back to front, and an explicit fall through is the right way to do it.

        I think that the C way is because it is much easier to parse an explict break statement. But Python doesnt care about making life easy for the parser, or it would use tokens rather than functional whitespace.

        1. As I recall, the MISRA (Motor Industry Software Reliability Association) guidelines for C programs prohibit, or at least advise against switch statements, specifically due to the high risk of unintended fall-through. This is the sort of cleverness that makes for bugs that fairly leap into code at the slightest opportunity.

          1. MISRA would mandate that brain surgery only be performed with spoons, to avoid the unacceptable risk of traumatic lacerations inherent in the use of knives.

          2. This is correct. IIRC It’s not a “Mandatory” but a “Required”, meaning you have to argue why you broke the rule if you did. It also requires a default case, and that the default case is defined last.

  1. Totally pointless. Yes, I get it: as long as you’re using a slow language anyway, you might as well throw in some more overhead, because it will get lost in the interpreter inefficiency anyway.

    This looks to me like the ternary (? :) statement in C – something that adds nothing but confusion. In none of the examples you’ve shown does this make things clearer, and in most cases it removes zero lines from the code.

    1. Speaking of confusion, does Python 3 still support the usual Python 2 syntax ?
      I mean, is is backwards compatible like C++ is to C – Or rather, is it backwards compatible like ANSI C is to K&R C ?
      Sorry for my ignorance, I rarely use Python.

      1. Largely, but no. In particular, print is a statement in Python 2 but a function in Python 3. Old style could be used as a function. Strings used to be interchangeable with bytestrings, now they’re not. Certain stuff can be written in 2 as forward-compatible, but not everything.

    2. Imo, as someone who uses Python daily, this is a welcome addition that will make long if-else if-else sequences easier to read and understand from a human perspective.

      If I were worried about scaling or runtime speed I would agree with the inefficiency statement. However, I think that most who use Python use it for quick prototyping, scripts that run occasionally, or research (my use case) and don’t need to worry much about that. Most operations in Python that are computation heavy or speed sensitive use packages that are themselves wrappers for a C library.

      1. I can not even describe how much I like to see such blocks in C++ including some other sourcery of dark magic in one line. Neat …. maybe. Easy to understand, fu## no.

        1. It is the objective of any programming language to prioritize clarity over compactness. The ternary operator simply should not exist. Was this in the original Python spec, or was it another thing that was added later to mess things up?

          1. Clarity is in the mindset of the beholder. While I agree that some choices are less clear than other available choices, I’ve never found ternary operators to be confusing… and the closer you end up having to work to the native silicon, the more the ternary operator makes sense (it’s a natural outgrowth of how compare-and-jump instructions work).

            I’d also argue that, while your statement about objectives might be nice as a prescriptive assertion, it’s erroneous as a descriptive statement.

          2. It was added later. But I think your view on the ternary operator is a bit extreme.

            I have a coworker who believes operator overloading should have never been a feature in C++, because “clever” programmers decide to use it for things they shouldn’t. But the thing is, for the right purpose, it’s *really* useful. For example, you’re writing a matrix class. Without operator overloading, you have to do something like a.mult(b), and now, how do you know if that’s left multiplication or right multiplication? It’s probably right multiplication, but you’ll have to double check. With a * b, it’s immediately obvious.

            The ternary operator is another one of those things that’s ripe for abuse, but can be very useful when used properly. In this case, “properly” means for things like default values, e.g.:

            a = b * 5 if b is not None else 0

            For really simple things like that, the operator is more digestible (assuming basic syntax highlighting) than the 4 lines it would normally require:

            if b is not None:
            a = b * 5
            else:
            a = 0

            Or in eafp style:

            try:
            a = b * 5
            except TypeError:
            a = 0

    3. For many of the things I do, performance is a distant secondary requirement. To me, being able to express concepts *the way I want to express them* is far more valuable through saving development time and increasing maintainability.

    4. I use the ternary conditional operator in C all the time, and its Python equivalent. They’re great. So much better at expressing the common idiom of assigning alternatives than a full clunky if statement, and typing the left hand side twice like some kind of barbarian.

      1. Yeah I don’t get the absolute hate on ternaries. IMO as long as they’re used for trivial purposes they’re just fine. My most common use case is inline selecting between two non-boolean constants, like `isOSThemeLightMode()? CUSTOM_THEME_LIGHT : CUSTOM_THEME_DARK`

        And it’s readable to me if you set the condition up as, and read it like, a question and answer. “Is the OS Theme in Light Mode? Gimme CUSTOM_THEME_LIGHT, otherwise gimme CUSTOM_THEME_DARK.”

        Complex conditionals or nested ternaries can fuck right off though. Keep it trivial.

      2. I use and love ternaries, but I treat them with kid gloves. My rule is generally “don’t do more than one ‘clever’ thing at a time” so a single ternary invocation is fine, but two or more (or a ternary mixed with something else) is to be avoided. That usually gives me extra expressiveness while staying easily readable.

    5. There is precisely zero fundamental reason for pattern matching to be slow; but it’s entirely possible to write a slow implementation.

      In any case, matching is not just “switch on steroids”, it’s an alternative approach to c++’s polymorphism. Which also used to be thought of as “slow”.

  2. In essence Switch/Match isn’t much more than a string of If statements.
    Saves in a few key strokes though.

    The switch examples outlined above could just be implemented on a machine code level as a list of “go to” with an overarching If statement to contain ourselves on the list.

    But the more nuanced statements shown in the Match examples bring forth a risk, we could fairly easily spiral down a computational nightmare where finding a mach could take longer than we might desire due to making unnecessary/redundant function calls instead of preprocessing our data and then feed it to our match function in a more easily processed format.

    Now, it isn’t “wrong” to have match as a feature. But I wouldn’t be surprised if it leads to a lot of poorly slapped together code. Not that there is tons of libraries that have such issues already. And I am not of the opinion that Match is a bad feature to have, just that it can be wise to consider its downsides. This is though true for almost anything.

        1. Then imho they’ve missed the mark with the choice of

          case _:

          over the historical

          default:

          Is a one character savings worth the lack of clarity that the word “default” more clearly communicates solely to retain the consistent use of “case” while introducing a confusing “_” to first time users?

          1. The _ might take getting used to, remembering its not a regular identifier in this position anymore (I see it used as localisation function or other common unnamed variables sometimes, like a dummy).

            Re: “default” – I think avoiding another keyword as that, has benefits, for existing code and api’s that might use that name, especially as a function parameter.

    1. Syntactically switch is just lots of if/else, although I wish there was an easy/portable way to indicate a jump table rather than if/else. Like, “I don’t care what these values are, make them so you can make a jump table later.”

      TI’s MSP430 compiler had an intrinsic to allow jump table instantiation easily, but of course it’s not portable.

      1. Fiddling with computer architecture design myself, I find jump tables particularly nice.

        They are simple and elegant and do a lot of stuff in a very neat fashion. Not to mention being exceptionally efficient if one has a reasonable amount of jump conditions.

        Though, jump tables together with more dynamically loaded/mapped code is “fun”….. Ie, when our program is made with a few piece of code that gets allocated into their own segments of memory, where we can’t during compile time know their relative positions. And yes, the solution is to build the table as part of the application itself during run time. Either by making the table itself, or assigning pointers elsewhere all though this is fairly pointless unless one has multiple paths making this jump.

      2. You should love cases in verilog then: You can specify exactly which bits you ‘don’t care’ about. Also, verilog doesn’t have C’s stupid default-fall-through behaviour.

        For example, here’s a forth cpu core in 126 lines:

        https://github.com/jamesbowman/swapforth/blob/master/j1a/verilog/j1.v

        It has four ‘casez’ statements, which allow for certain cases to be ‘don’t care’ bits in the pattern matches.
        This makes the opcode decoding particularly clear and neat.

        The other three control the data and return stacks, and the program counter behaviour.

        It uses the main ram memory bus mostly to fetch instructions, but can also use it to fetch data if required, which is done by using the msb of the program counter (right at the top of instruction decode).

        Otherwise the core completes instructions one per cycle, essentially a hardware ‘forth’ stack machine, but without all the ram access overhead of implementing stacks by having just the stack pointer be a register – in this one, each stack takes the place of registers, so there’s no time wasted.

        This is good enough to run classic 16bit ANS forth code with very little porting effort, and in a $10 FPGA it can be made to execute at ~30M forth words per second.

        A forth-word call costs an overhead of exactly one extra instruction cycle – the core can implement both ‘jump’ as well as ‘call’ in hardware, and the return PC behaviour is encodeable into any saved ‘alu-type’ instruction, so it’s essentially ‘free’ with the last instruction in the subroutine.

        Note how this works on lines 109/110: Verilog’s case statements allow you to match multiple patterns also, with a list separated by a comma. In this case, the same thing is done on the cycle used to fetch data from ram as for the last alu cycle in a subroutine call: the return stack is popped back into the program counter.

    2. Switch statements are exact coding analogues to finite state machines.

      A switch statement inside an infinite loop, using enumerated values named for the switch states, makes for a completely readable organization of the FSM layout.

      Each case statement is a state, and the code of each case statement can test for conditions and set the state to another one, or stay in the same state as needed. Then break to re-execute the loop. Done.

      (The infinite loop doesn’t need to be a spin loop – the loop can wait on an interrupt; for example, timer tick or external interrupt.)

      Laying out the code in this manner leads to good programming. If you take the rule that each state has to know definitely what the next state should be, you quickly find gaps and holes that weren’t covered in the specifications. For complicated situations involving external data and user interaction, this is wildly useful for eliminating bugs at the outset. You frequently find such gaps, and can then go back to the design and think through the use case.

      Switch statements are not syntactic sugar, even though they can be easily replicated with “if” statements.

      (Also, some architectures have specialized assembler instructions that make switch statements really fast. Some sort of table lookup generated by the compiler will jump to the correct state immediately without having to chain through all the if statements. Some compilers will optimize 3 or more chained “if” statements to take advantage of this.)

    3. i hate to imagine what python’s internals look like, but in C, that’s not really true. in principle, you might imagine a C compiler can convert chained if-else into a switch statement internally, but i haven’t heard of any compilers actually doing it. but i know for a fact that even relatively simple C compilers generally have a variety of techniques for implementing switch statements, often chaining together multiple techniques.

      jump tables for dense cases, of course.

      tricks with bitmasks: switch(x) { case 0: case 2: case 4: case 6: foo(); } => if ((x&~1)<8) foo();

      single comparisons.

      range checks.

      decomposition…use range checks to divide the switch statement into different regions, some of which may be dense enough to support a jump table, others may fall back to bitmasks or even single comparisons.

      even if it still winds up with chained comparisons it's often possible to do them in a fashion similar to a binary search, where it's O(lg n) instead of O(n).

      and of course if you're matching by strings, then you wind up with the whole lexing question, a lot of old basic research has shown efficient techniques for that.

      switch/case is really amenable to a wealth of different implementation strategies, while chained if-else would only be amenable to that basically if some front-end step converted it into a switch/case.

      1. Having a Switch function is in itself not bad.
        It does make the compiler’s job a bit easier since it can more clearly see one’s intent.

        Though, there is a lot of places in code where most languages makes it a bit hard to properly convey one’s intentions in an effective manner. One can look at something as simple as having a list of strings, here we can optimize for memory, or performance, but a compiler is going to have a hard time to just know what of those one actually wants/needs.

        But back to the topic of Switch.

        If we have a list of IF statements, then our compiler would need to make more considerations compared to if we just use a Switch. I think the Switch function is useful, even though it technically isn’t anything more than a bunch of IF statements.

        How one implements it in machine code is though a different question. And this is generally where our complier does the heavy lifting, or at least tries to.

        If we should break down our Switch function into a set of IF statements or a jump list or potentially some hybrid of both, would all depend on the code we want to compile. But the Switch statement at least makes our intent more clear and removes some of the burden from our complier.

        Match on the other hand supports much more nuanced IF statements, something that introduces a new can of worms for our complier to wrangle. If this is for better or worse I am not going to dabble too much into myself.

  3. Such a match style switch state statement has been part of the ruby programming language for centuries. Ruby is so much easier and cleaner than python, but somehow python is more popular.

  4. And it’s going in another incremental version of python so yet again will contribute to the parochial nature of the language – ‘it works in my local variation of python 3.something but not in your slightly earlier version’.

    Won’t they ever learn ?

    1. Python is the dynamic language version of C++. Throw in anything and everything anyone “important” wants. Many of the larger libraries, for both languages, take the same path. You end up with $50 books going out-of-date in 6 months. It is what it is at this point. Many must simply play ball to pay the rent.

  5. For those wondering how this is new and why python does not have a case-switch statement like other languages: the standard solution for a switch in python is using a dictionary since like forever. A dictionary must have unique keys, meaning anything hashable – even user-defined objects – can be a key. Calling cases not handled raises a KeyError should be caught in a try-except block. The switch-case statement that will be implemented is more flexible than this solution as it enables expressions to be used as “keys”.

    1. This! I actually like Python’s dictionary “case”. If you’re making a state machine, it puts the states and their handlers, the business logic, all in one place.

      It’s also like the way I do them in C: enum’ed array of pointers to functions. Same thing, really, but a bit nicer in Python.

      In both cases, they’re faster than the “if/then” equivalents. Dictionary lookup in Python is surprisingly speedy.

      I _do_ see how this confuses non-Python people when they come to the language, though, so I get the need for a “case”. And of course, nothing’s going to stop you from writing it the old way. Just now, there are two ways to do the same thing. (Yay! (Sarcasm.))

      1. The enumerated array of function pointers is not even close. Functions need to be of the same signature. So just a glorified lookup table. In the end they end up taking void pointers in and out all day casting them to who-knows-what type.

  6. i’m torn. i feel derision that python didn’t have this already. such a rich type system, this kind of matching construct is the sine qua non! but i also see the promise, as this bears some superficial resemblance to the powerful matching system at the heart of functional languages like ML.

    i think the performance hit is a red herring. *everything* in python is slow. every single finished python program is at least 1000x slower than it should be. i mean, i know people like to hem and haw around potential, but looking at real life examples that’s a hard lesson to ignore. but the flipside is, ML is entirely focused around this kind of pattern matching and ML is very fast.

    i had a decently complicated data type i’d implemented in C (a binary tree representation of a sparse bit vector), and looking for a game to play to learn ML, i realized this data type would be a good fit for ML. not only was the expression of the data type and its algorithms much simpler in ML (precisely because of this kind of pattern matching) than in C, but the built-in ML reference counting memory management was better than the poorly-thought-out reference counting i’d done in C. until i fixed up the C reference counting, the unoptimized naive ML version was actually *faster than tuned C*, despite a severe handicap from ML’s general inability to represent a 32-bit int!

    it’s possible to do really expressive type-based logic in a very efficient way in a compiled language…python is just slow because it just implements everything in the most straight-forward interpretted fashion. *shrug* i’m not even knocking python. i mean, i use perl all the time and it’s slow as a dog too, for roughly the same reason.

  7. It doesn’t have to be that performance intensive. Think about it: each Python object has a type, which is an object on its own. So if you do type comparison, you just check the type pointer. To check the value, you check the value of the object. Figuring out which comparison’s needed is a (bytecode) compile time determination, so there’s no real performance issue.

  8. Please, somebody, tell me that this is just a bad april fools joke.
    – it is just a fancy syntactic sugar on elsif
    – it adds one more indent level over elsif
    – fact that language survived three decades without it showed that it is not necessary
    – it could also be done better with dictionaries
    – I could go on…

    1. i feel the same way. my complaints are as followed:

      1. a break statement is not confusing
      2. a fallthrough is useful in many situations and is only “bug prone” if you don’t break cases
      3. in the final “powerful” example. you have if statements. so why not just use if statements
      4. since when is an “if else” statement a ladder?! the computer reads top to bottom
      5. a ternary statement is not confusing. conflating if else statements with other syntax is deeply confusing though

      p.s. i don’t use python. this has done nothing to make me want to use it either.

  9. Looks like not just match, but match with destructuring, which is pretty powerful for writing concise clear code. I do enjoy it in the bit of rust I’ve coded.

    Glad no default fall through.

    Kotlin has a nice solution to the “what am I breaking from” problem: break and return inside of nested constructs sometimes (? not sure the rules, I let the ide help me) have an annotation starting with @ saying what exactly you’re break and return-ing from. Kind of surprised that’s not a more widely adopted feature.

  10. I probably won’t use it. Most all of my Python applications will run from 3.3 to latest. More portable that way. I try to stay with the core of the language instead of using the ‘gasp’ newest, or hard to understand features. If I have a hard time with it … what will the next person have to deal with it when he/she starts maintaining it. If, elif, else work fine for me. I write ‘lots’ of python code for work and at home.

  11. Your comment on why the C efficiency is so much better, is not completely accurate. The C version of switch is not always compiled to a series of constant time comparisons. It can sometimes be implemented as a table lookup where it can be done constant time with regard of the number of cases. See https://godbolt.org/z/j4e4hGssf

  12. i’ve been using this as a switch-like function in python. can’t remember where I first saw it but it mostly works as needed/wanted

    def switch(command,arg):
    switcher = {
    ‘VER’: version,
    ‘GET’: partial(get, arg),
    ‘GETS’: partial(gets,arg),
    ‘LOAD’: partial(load,arg),
    }

    func = switcher.get(command, lambda: “‘not a command\n”)
    return func()

  13. “The developers were concerned about confusion if a break statement were called inside a match statement inside a loop — what breaks then, the loop or the match? Here, the first case that is satisfied is executed, and the statement returns.”

    I always found being able to fall through cases was a useful feature that saved me from having to duplicate code or write much less readable nested combinations of multiple if and switch statements.

    I get so frustrated in C# where you can fall through but only if there are not statements between cases. Often I find myself needing to do this:
    If a do x, if b do x and y, if c do z.

    This is perfect:
    switch foo
    case b:
    do y
    case a:
    do x
    break;
    case c:
    do z;
    break;

    Without that ability either x has to be factored out into a separate method which just makes the flow harder to read or it has to be copy/pasted which is also a bad practice as it complicates maintenance.

    I have never found the “which level does it fall out of” question to be confusing in the slightest. Obviously it would fall out of the innermost block just like in any other language. Unless like in a few languages you allow the user to pass an optional int to break. If you can’t see what it’s going to break out of then you must be indenting poorly but how do you do that in Python?

    And yes, I do like to indent the case statements. I don’t care what the purists say, it’s easier to read that way. The case statements only make any sense as parts of the switch statement so that relationship should be displayed visually. I don’t always un-indent the break statements like this because doing so requires fighting the formatting rules of pretty much any code editor but I did when I used a “dumber” editor and I still think it would be ideal.

    It seems (my own personal opinion) that so much change in computers these days is about solving strange non-problems by removing good functionality.

    But hey, at least it’s something like a switch statement. Better than nothing I guess.

    1. Well, comment system ate my spaces and every time I try to post with & n b s p ; in there all I get is “invalid security token”.

      Picture one level of indent in front of each case and break and two levels in front of each do.

    2. If you want C style switch case statements in Python simply use a dictionary. Has the added advantage that the case can be any hashable value, and since you can add a hash function to pretty much anything in Python… Lots of possibilities.

  14. So they find a break statement confusing, but add a switch construction that sometimes changes the value of the thing you are comparing ?

    Kind of one of those “constructions” a language has but are not meant to be used.

    1. Raku would surprise many when they find it has better expressiveness for functional programing idioms than most dedicated functional programming languages, this one included.

  15. I program industrial robots and the programming language is called Rapid. They have a function similar called “test” in which only a single case is executed based on what your parameter was passed in. It in fact uses the exact same structure

    TEST var
    CASE 1:

    DEFAULT:
    ENDTEST

  16. This will be fun _and_ a biiggg challenge for the creators of “Micro Python” to implement “some” of this match functinality to run on a micro controller.
    IMHO the whole Python thing is very usefull for people who need to do some sort of programming but their skills and interest is not the programming but using it as a tool. (i was a realtime programmer).

    1. It appears to be much simpler to implement than some of the features they have already implemented, since it depends only on elements already available to the AST/recognizer.

  17. Evaluating this solely as a replacement for chained if/then/else statements or switch/case statements is insufficient. What Python has introduced here is a feature that is cribbed from “functional” languages like Haskell or Elixir and presumably Erlang where signature matching and multiple dispatch is just how things are done. Until you see it in use and are a little conversant with that paradigm it is far too easy to dismiss this as being too complex because it is purposefully much more than a replacement for chained if/then/else and can lead to much more expressive and reliable code. Many newer languages are incorporating this as one of the truly valuable features to take from “functional” programming.

  18. There is a way to do case switching in Python right now: use a dictionary. That’s probably why the devs didn’t just put an average, old C style case statement in there.

    1. 1. So you advocate for stagnation? We should all still be using Turing’s bombe because everything that came after it was incompatible with previous versions?
      2. This doesn’t introduce incompatibility with previous versions, as it is understood. No one anywhere is trying to maintain forwards compatibility (as in present code being run in older environments). The only thing that matters is backwards compatibiltiy, and this doesn’t stop Python 3.10 running any code written for previous Python 3.x versions.

      1. I have plenty of code for Python 2, which was at that time “best thing since sliced bread”. Either they were lying then, or they are lying now.

        Steering wheels were round for more than 100 years. Should we make them square?

        Not every change is good, in other words.

        1. So you do agree that we should have just stuck with Turing’s Bombe and never improve over it?

          And just so you know, standardization does not imply stagnation. Python 3 is a standard. So is this new switch statement.

  19. Without waiting for this new control structure, a simple way to avoid the insane “ladder effect” of a long “if elsif elsif … elsif” list could be using a “for” loop on “range(1)”

    kase=17
    for i in range(1):
    if kase==1:
    print(‘whatever 1’)
    break;
    if kase>17:
    print(‘whatever more than 17’)
    break;
    ### if :
    ### …
    break;
    ### ….
    print(‘whatever defaut’)

    works also fine in PHP and other languages with a “do { … } while(false);” control structure. Using plain predicates, it may be used to deal with non scalar types (C).
    I recently discovered that GO stock “switch” control structure works similarly.

    If you like it cryptic, using boolean evaluation may also do the work ;-)
    (pred1&&func1() || pred2&&func2() || …)

    1. That’s not a very good way of doing it. Python has dictionaries, which is the exact reason why Python has never had a switch case structure and why this new functionality is not a simple switch case structure.

    2. Somebody please enlighten me: what is wrong with a sequence of if-then-else-if things? It is easy to follow what’s going on, at least if you don’t nest if-then-elses within the thens or the elses. I don’t understand what the problem is that this is supposed to fix.

      1. This is not a replacement for if-then-else chains, nor is it a replacement for switch. To gain understanding I would suggest learning about pattern matching and multiple dispatch in “functional” programming languages like Haskell or if you are already familiar then I hope you now see the similarity and purpose.

      1. i see having to spend more time debugging weird python incompatibility issues
        like if some library had an unfortunate variable named “switch” or “case” it’d have to be redone, then it’d potentially be incompatible with the projects that use it and so on

        1. Aside from name collisions, nothing, then? That is something that is quickly corrected with automation.

          There is much I like about Python but its lack of support for functional programming idioms is not one of them. This is a good step forward, in my opinion.

  20. Great new feature. I would drop the leading “case” keyword, though. The introducing “match” says it all already, no need to prefix every case explicitly with “case”.

    Looks cleaner and more readable.

    1. TL;DR – I see the power of the matching, but even though I sometimes find switch useful I just don’t see this as a huge improvement apart from losing the repeated variable references in the nested elif statements it’s replacing. Maybe I just don’t them enough to see the savings or don’t yet fully appreciate it enough.

      If the lack of the “case” keyword doesn’t create a problem for the lexical interpreter…why not this:

      switch (x) :
      :
      # Do something
      :
      # Do something else
      else:
      # Default action

      Or even this; to borrow from the if/else heritage some more:

      switch (x) :
      :
      # Do something
      :
      # Do something else
      else:
      # Default action

      In either case, use of “else” is just as intuitive as “default”, but way more so than “_”; plus it matches the if/else you’re accustomed to but replacing [while appeasing the C/Perl haters by not using “default”]. Of course at this point you’ve only really gotten rid of a few “elif x …” statements. Hmm, “elif” vs. “case” tokens…no savings there. So the repeated references to “x ” before each pattern and the removal of “break” are the only real savings here since the fancy pattern matching can be done with if/else tree and those don’t need breaks to begin with, yeh? I’m discounting the “guards” that were mentioned. Given how many have a extreme distaste for ternary expressions or have bagged on Perl for being hard to read when the same sort of trailing conditionals are used, I guess you have to create a new word for the concept in order to avoid the torches and pitchforks. Personally I like ternaries but think the Python syntax for these doesn’t read as nicely as the classic “expression ? true : false”.

      I also think some of the examples provided above might prove a bit hard for the first time coder to comprehend and thus don’t live up to Python’s legacy of simplicity. I’m not knocking them or the power match() could provide, but similar to the insults thrown at Perl in the past for its murky syntax, I felt some of them just wouldn’t be super intuitive to everyone at first glance or at least they weren’t for me.

      For the folks wishing they had break or continue, I agree for the most part Add them both to a match statement and you’ve basically created another form of loop control. If thought of in that context, it doesn’t seem difficult to think of “break” in terms of the innermost loop and thus nested inside a true loop control shouldn’t prove hard to understand. As for “continue”, since I’ve mentioned Perl a couple of times already, let’s just borrow “next” to avoid any confusion with “continue”, especially if we don’t get the “break” we want, and thus don’t have that new “loop” to worry about.

      TL;DR – I see the power of the matching, but even though I sometimes find switch useful I just don’t see this as a huge improvement apart from losing the repeated variable references in the nested if/else tree it’s replacing. Maybe I just don’t use those enough to see the savings or don’t yet fully appreciate it enough.

      :-P

Leave a Reply

Please be kind and respectful to help make the comments section excellent. (Comment Policy)

This site uses Akismet to reduce spam. Learn how your comment data is processed.