Skip to content
VLSI Mentor

Python Part I · Module 9 · Conditional Statements

match for Dispatching on Tool and Status

One pattern recurs in every script that talks to tools: a single value is compared against a list of known possibilities, and each one leads somewhere different. Which simulator is this. Which result class is this. An elif chain does the job and says the same thing over and over — the name of the value, the equals sign, the candidate — until the structure of the question disappears into repetition. Python has a statement designed for exactly this shape. It is clearer, it enforces something an elif chain cannot, and it contains one trap that is worth more attention than all of its syntax: a case that looks like a comparison and is not.

Intermediate15 min readPythonPart IFundamentalsConditionalsmatch

Part I · Module 9 · Chapter 9.8 · match for Dispatching on Tool and Status

1. The Chain That Repeats Itself

Here is a dispatch written with the tools you have:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sim = "xrun"

if sim == "vcs":
    tool = "Synopsys VCS"
elif sim == "xrun":
    tool = "Cadence Xcelium"
elif sim == "questa":
    tool = "Siemens Questa"
else:
    tool = "unknown"

print(tool)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Cadence Xcelium

It is correct, and it is doing something Chapter 9.1's chains were not. Every condition tests the same value against a different candidate, so sim == appears three times and carries no information after the first. The shape of the question — which of these is it — has to be inferred from the repetition.

2. The Same Dispatch as a match

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sim = "xrun"

match sim:
    case "vcs":
        tool = "Synopsys VCS"
    case "xrun":
        tool = "Cadence Xcelium"
    case "questa":
        tool = "Siemens Questa"
    case _:
        tool = "unknown"

print(tool)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Cadence Xcelium

The value is named once, at the top. Each case carries only the candidate. The structure now states itself: one subject, several possibilities, one of which applies.

3. How It Runs

The mechanics are the ones you already know from Chapter 9.1, with one addition:

  1. the subject — the expression after match — is evaluated once
  2. each case pattern is tried from top to bottom
  3. the first one that matches selects its block
  4. the rest are skipped, and the statement ends

Only step 2 is new, and only in what "matches" means. For the patterns in this chapter, a pattern written as a literal matches when the subject is equal to it — so case "xrun": behaves like sim == "xrun".

Everything else transfers unchanged. First match wins; exactly one block runs. The indentation rules from Chapter 9.2 apply at both levels — the case lines are indented under match, and each body is indented under its case.

The claim that later cases are not evaluated can be tested the same way Chapter 9.1 tested it for an elif chain. Put something in a later case that could not survive being evaluated:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = "PASS"

match status:
    case "PASS":
        verdict = "ship"
    case other if 1 / 0:
        verdict = "impossible"

print(verdict)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ship

The guard on the second case contains a division by zero and does not raise, because the first case matched and Python stopped there. This is the same mechanism as the elif chain, the and guard in Chapter 9.3, and the untaken half of a conditional expression in Chapter 9.6 — the fourth construct in this module to behave this way, and the clearest sign that it is one rule rather than four.

The subject is also evaluated once, not once per case, which matters when it is an expression rather than a name:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
counts = {"errors": 3}

match counts["errors"]:
    case 0:
        print("clean")
    case 3:
        print("three errors")
    case _:
        print("other")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
three errors

counts["errors"] is looked up a single time, and the resulting 3 is what every pattern is compared against.

4. Several Values, One Outcome

When two candidates lead to the same place, | joins them into one pattern:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = "WARN"

match status:
    case "PASS":
        verdict = "ship"
    case "FAIL" | "FATAL":
        verdict = "block"
    case "WARN":
        verdict = "review"

print(verdict)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
review
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = "FATAL"

match status:
    case "PASS":
        verdict = "ship"
    case "FAIL" | "FATAL":
        verdict = "block"
    case "WARN":
        verdict = "review"

print(verdict)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
block

Read | as or. The equivalent condition is status == "FAIL" or status == "FATAL", or the membership test from Chapter 9.3 — and case "FAIL" | "FATAL": is the tidiest of the three, because the alternatives sit where the single candidate would.

5. Conditions on a Case

A pattern can carry an extra condition, written with if after it. This is called a guard, and it is checked only when the pattern itself has matched:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors = 7

match errors:
    case 0:
        band = "clean"
    case n if n < 10:
        band = "minor"
    case _:
        band = "major"

print(band)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
minor

The subject is an integer here, not a string — match works on any value. case 0: is a literal pattern. case n if n < 10: captures the subject as n and then applies the guard, so it matches any value below ten that was not already caught by case 0:.

Guards are where branch order comes back. case n if n < 10: sits below case 0:, so zero never reaches it — exactly the reachability reasoning from Chapter 9.1, now applied to cases.

6. The Unknown Case

Without a final catch-all, a value that matches nothing simply falls through and nothing happens:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
sim = "questa"
matched = "nothing ran"

match sim:
    case "vcs":
        matched = "vcs"
    case "xrun":
        matched = "xrun"

print(matched)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
nothing ran

No error, no warning, no output from the match at all. In a script that dispatches on a tool name, that is the worst possible behaviour: an unrecognised simulator produces a run that looks like it did something.

case _: is the wildcard. It matches anything, and it is where the unknown case gets reported:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sim = "questa"

match sim:
    case "vcs":
        tool = "Synopsys VCS"
        ok = True
    case "xrun":
        tool = "Cadence Xcelium"
        ok = True
    case _:
        tool = sim
        ok = False
        print("unrecognised simulator:", sim)

print(tool, ok)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
unrecognised simulator: questa
questa False

The unknown value is named in the message rather than being hidden, and the result records that nothing valid was selected.

7. The Trap: A Bare Name Is Not a Comparison

This is the one thing to take from the chapter if you take nothing else.

A pattern written as a plain name does not compare the subject to that name's value. It is a capture pattern: it matches anything at all, and binds the name to the subject.

Here it is with a constant, which is how the bug actually reaches real code:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
VCS = "vcs"
sim = "questa"

match sim:
    case "xrun":
        print("xrun")
    case VCS:
        print("entered the VCS arm")

print("VCS is now", VCS)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
entered the VCS arm
VCS is now questa

Two things went wrong and neither raised.

The arm was entered although sim is "questa" and VCS is "vcs" — because case VCS: asked nothing. It matched unconditionally, exactly as case _: would have.

And VCS now holds "questa". The constant was overwritten by the match, because binding the subject to the name is what a capture pattern does.

The fix is to write the literal:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sim = "questa"

match sim:
    case "vcs":
        print("entered the vcs arm")
    case "questa":
        print("entered the questa arm")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
entered the questa arm

8. The Wildcard Goes Last

Python enforces the same reachability rule for _:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
sim = "vcs"

match sim:
    case _:
        print("anything")
    case "vcs":
        print("vcs")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  File "bad.py", line 4
    case _:
         ^
SyntaxError: wildcard makes remaining patterns unreachable

This is a pleasant difference from the if/elif chain, where Chapter 9.1's unreachable branch — score >= 95 written below score >= 80 — ran happily and reported the wrong answer. Python cannot detect that in general, but it can detect a catch-all with cases beneath it, and it does.

9. match and case Are Not Reserved Words

One detail surprises people who have just learned that match is a statement: it is not a keyword in the ordinary sense. match and case are soft keywords — they act as keywords only in the positions where a match statement is legal, and remain available as ordinary names everywhere else.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
match = "still usable as a name"
case = 4210

print(match)
print(case)

match match:
    case "still usable as a name":
        print("and match still works as a statement")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
still usable as a name
4210
and match still works as a statement

A variable called match and a variable called case, followed by a match statement whose subject is the variable match. All of it is valid.

This was deliberate. match was added in Python 3.10, long after a great deal of code had already used match as a variable name — the result of a search is the obvious example. Making it a reserved word would have broken that code on upgrade, so the language accepts it in both roles and decides from position which one is meant.

10. What This Chapter Does Not Cover

match is substantially larger than the four pattern kinds used here. It can destructure a list into its parts, match a dictionary by the keys it contains, and check the type and attributes of an object in one line.

Those are genuinely useful and they are not foundation material — several of them need classes, which are Module 16. What this chapter has given you covers the dispatch case completely:

PatternWrittenMatches
literalcase "vcs":the subject equals that value
or-patterncase "FAIL" | "FATAL":the subject equals either
capturecase n:anything, and binds the name
guardcase n if n < 10:the pattern, then the condition
wildcardcase _:anything, binding nothing

11. match or elif

Neither is a replacement for the other.

UseWhen
matchone subject compared against several candidate values
if / elifconditions that test different things, or ranges, or compound logic

A chain like this is not a dispatch and should stay as it is:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
errors = 0
warnings = 3
finished = True

if not finished:
    verdict = "incomplete"
elif errors > 0:
    verdict = "FAIL"
elif warnings > 0:
    verdict = "PASS with warnings"
else:
    verdict = "PASS"

print(verdict)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
PASS with warnings

Three different quantities, three different questions. There is no single subject to put after match, and forcing one would obscure the logic rather than reveal it.

The test is simple: if you can write the value once at the top and have every branch be a candidate for it, match fits. If you cannot, it does not.

12. Predict, Run, Observe

Predict all four before reading on. One of them produces no output from its match at all.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# A
status = "FATAL"
match status:
    case "PASS":
        print("A: ship")
    case "FAIL" | "FATAL":
        print("A: block")
    case _:
        print("A: unknown")

# B
n = 0
match n:
    case 0:
        print("B: clean")
    case m if m < 10:
        print("B: minor")
    case _:
        print("B: major")

# C
sim = "icarus"
match sim:
    case "vcs":
        print("C: vcs")
    case "xrun":
        print("C: xrun")
print("C: after the match")

# D
mode = "fast"
match mode:
    case "fast" | "slow":
        print("D: known mode")
    case _:
        print("D: unknown mode")

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
A: block
B: clean
C: after the match
D: known mode

A — the or-pattern matches "FATAL", so the wildcard is not reached.

B — case 0: matches first. The guard below it is never tried, which is why a zero never reports as "minor".

C — nothing matched and there is no wildcard, so the match produced no output at all. The line after it still runs. This is Section 6's silence, and the only evidence of it is a missing line.

D — the first alternative of the or-pattern matches.

13. Exercises

Exercise 1 — convert both ways. Rewrite the Section 1 chain as a match, and rewrite the Section 10 chain as an if/elif. Say which conversion improved the code and which did not.

Exercise 2 — the capture trap. Write a match with a constant XRUN = "xrun" and a case XRUN: as the final arm, with a subject that is not "xrun". Predict the output, run it, and then print the constant afterwards. Explain both results in two sentences.

Exercise 3 — when Python warns. Take your Exercise 2 program and add one more case beneath the capture. Record the exact error. Explain in one sentence why Python can detect the problem in this version and not in the previous one.

Exercise 4 — the silent fall-through. Write a match with two cases and a subject matching neither, and arrange the program so the omission is detectable from the output. Then add case _: and show the difference.

Exercise 5 — or-patterns. Rewrite if s == "a" or s == "e" or s == "i" or s == "o" or s == "u": as a match with one case, and also as the membership test from Chapter 9.3. Say which you would use and why.

Exercise 6 — guards and order. Write a match on an integer error count that reports clean for 0, minor below 10, major below 100 and critical otherwise. Verify it at 0, 1, 9, 10, 99 and 100, and say why those six values are the right ones.

Exercise 7 — choose the construct. For each, say match or if/elif and why in one sentence: (a) classifying a status string (b) deciding from a coverage percentage (c) selecting behaviour per simulator name (d) checking whether a run both finished and was clean (e) mapping a one-character severity code to a word.

Exercise 8 — dispatch with a guard. Write a match on a simulator name that recognises vcs and xrun, treats questa and modelsim identically, and reports anything else by name. Then add a guard to one arm so that an empty string is reported separately from an unknown tool.

14. Summary

  • match fits one subject compared against several candidate values — the shape an elif chain expresses by repeating subject == on every line.
  • The subject is evaluated once, patterns are tried top to bottom, the first match wins, and the rest are skipped. The same rules as a chain.
  • A literal pattern matches when the subject equals it.
  • | joins alternatives into one pattern: case "FAIL" | "FATAL":.
  • A guard adds a condition to a case, checked only after the pattern matched.
  • Without case _:, an unmatched subject produces silence — no error, no output, nothing.
  • Write case _: and name the unrecognised value in it. Chapter 14.7 adds the stronger option of stopping the program deliberately.
  • A bare name is a capture pattern, not a comparison. It matches everything and rebinds the name — including a constant you meant to compare against.
  • Python rejects a capture or wildcard that has cases beneath it, and cannot help when it is last, which is where it is most likely to be written.
  • The subject is evaluated once, and a later case's guard is never evaluated after an earlier case matched — the same rule as the elif chain, the and guard and the conditional expression.
  • match and case are soft keywords, still legal as variable names, because the statement arrived in 3.10 after a great deal of code already used those names.
  • Use if/elif for different questions, ranges and compound logic. If the value cannot be written once at the top, match does not fit.

That closes Module 9. You can now express a decision, read its structure from the indentation, write the condition exactly, nest or flatten it deliberately, use any value as a condition, produce a value instead of selecting statements, and dispatch on a subject — and you know what an if actually does when it runs.

Every decision so far has been made once. The next module is about doing something repeatedly, and about the loop variable that makes a decision apply to every item in a collection rather than to one.

Where this fits

Part of the Python curriculum.