What does `case _:` match in a Python match statement, and where must it appear?
answer
- One pattern can never fail
- Matches anything, assigns nothing
- Its position in the case list is forced
- A later case is a compile-time SyntaxError
- Single underscore, not a capture name
basics
~20 scase _: is the wildcard pattern: it matches any subject and binds nothing, so the name _ keeps whatever value it already had. Because it always succeeds, it must be the last case in the match statement.
solid answer
~50 sThe single underscore is a dedicated **wildcard pattern** in Python's structural pattern matching (3.10, PEP 634), not an ordinary name. It succeeds against any subject at all — including `None`, an empty list or an object of a type no other case mentions — and it performs no assignment, so a module that already uses `_` for something else (a translation helper, the REPL's last-result name) is not clobbered by running a match. Because a wildcard can never fail, the compiler forbids anything after it: a case following `case _:` is a compile-time `SyntaxError` reading "wildcard makes remaining patterns unreachable". Inside a larger pattern `_` is still a wildcard and may repeat, as in `case [_, _]:`. A `case _:` is optional; adding one is how you give a match statement a default branch, since the grammar has no `else` clause.
code
python · 12 lines_ = "not touched by the wildcard"
def route(status):
match status:
case 200:
return "ok"
case 404:
return "missing"
case _:
return "unexpected"
print(route(200), route(500), _)go deeper
Recall two facts and you pass this one: case _: matches anything, and it goes last. Be ready to say out loud that it does not assign the subject to _.
Explain the mechanics: the wildcard is a distinct pattern form, irrefutability is what forces the position, and the check happens at compile time as a SyntaxError rather than at runtime.
Show judgment about what belongs in that final case. In production code over a closed set of inputs, an empty catch-all is a silent data-loss bug; a raising one names the offender.
Own the convention across a codebase: whether catch-alls raise, log or pass should be a stated rule rather than per-author taste, since the three choices have very different failure behaviour under unexpected input.
Python's `match` statement, added in 3.10 by PEP 634, compares a subject against *patterns* rather than against values, and inside that pattern grammar a single underscore is its own syntactic form: the **wildcard pattern**. This matters because `_` means something quite different everywhere else in the language. In ordinary code `_` is just an identifier, used by convention for a value you intend to discard (`for _ in range(3)`), and by the interactive interpreter for the last evaluated result. Inside a `case`, the compiler does not treat it as an identifier at all. ### It always succeeds A wildcard matches any object. There is no type it fails on, no value it rejects, no emptiness it objects to. `case _:` will match `None`, `0`, `""`, an empty dict, an instance of a class defined after the match was written — anything. That total irrefutability is the whole point: it is the branch you reach when every earlier case has failed. ### It binds nothing This is the detail interviewers actually probe. A bare name in a pattern is a *capture*: writing `case value:` also matches everything, but it assigns the subject to `value`. The wildcard does neither half of that — it matches and then walks away. So after ```python _ = "translation helper" match 42: case _: pass print(_) ``` `_` still prints `translation helper`. Nothing was written to it. The practical consequence is that inside a `case _:` body you cannot refer to the subject via `_`; if the body needs the value, either name the subject expression in a variable before the `match`, or use a capture name in that final case instead of the underscore. The same rule explains an asymmetry that looks arbitrary until you know it. `case [_, _]:` is perfectly legal, because two wildcards make no assignments and so cannot conflict. `case [x, x]:` is a `SyntaxError` — "multiple assignments to name 'x' in pattern" — because a pattern may bind each name only once. The underscore is exempt precisely because it binds nothing. ### Its position is forced PEP 634 calls a pattern that cannot fail *irrefutable*, and requires that an irrefutable case block, if present, be the last one. This is checked when the code is compiled, not when it runs, so it fails at import time rather than in production: ``` SyntaxError: wildcard makes remaining patterns unreachable ``` A bare capture name in a final-ish position gets the parallel message, "name capture 'x' makes remaining patterns unreachable". Python is unusual here — many languages let you write unreachable branches and merely warn — and the strictness is deliberate: an unreachable case is always a mistake, so the language refuses to compile it rather than silently ignoring it. The rule is about *irrefutability*, not about the underscore character. Attach a guard and the case can fail, so it is no longer irrefutable and may be followed by more cases: ```python match n: case _ if n > 100: ... case 0: ... case _: ... ``` That compiles and runs, because the guarded wildcard is only reached-and-taken when the guard is true. ### It is optional, and that is the trap Nothing requires a match statement to end with a wildcard. A match whose cases all fail simply does nothing and execution continues at the following statement — no exception, no warning. So `case _:` is not merely stylistic sugar; it is the only mechanism the statement offers for a default branch, because `match` has no `else` clause in its grammar. In code where the subject is drawn from a set you believe is closed — a status code, an enum member, a message kind — the strongest thing to put in that final wildcard is a `raise`, with the unmatched subject interpolated into the message so the failure names itself. In code that deliberately filters a heterogeneous stream, an empty `case _: pass` is honest and worth writing explicitly, so the next reader can see that falling through was intended rather than forgotten. ### What to say in an interview Wildcard, not a name. Matches anything, binds nothing. Must come last, enforced at compile time by a `SyntaxError`. Optional — and when the domain is closed, make it raise.
- Can a wildcard case carry a guard, and does that change where it may appear?Yes. `case _ if total > 100:` is refutable — the guard can be false — so it is no longer an irrefutable case block and further cases may follow it legally. Only a *bare* `case _:` (or a bare capture name) triggers the "makes remaining patterns unreachable" `SyntaxError`. That is the escape hatch when you want a catch-all shape early in the case list.
- Why may `_` appear twice in one pattern when a capture name may not?Because the wildcard performs no assignment, so two of them cannot conflict. `case [_, _]:` is fine. A capture name binds, and a pattern may bind each name only once, so `case [x, x]:` is rejected at compile time with "multiple assignments to name 'x' in pattern". Pattern matching never does the equality check that repeated name would imply — you need a guard for that.
- Inside a `case _:` body, how do you get at the value that was matched?Not through `_` — it was never assigned. Either bind the subject to a name before the `match` statement and read that name, or make the final case a capture such as `case other:`, which also matches everything but does bind. A capture in the last position is legal for the same reason a wildcard is: it is irrefutable and it is last.
Think of _ as a blank tile in a word game: it fits any slot on the board, but no letter is ever written down for it.
saying these in an interview costs you the question
- Says `case _:` binds the subject to the name `_`
- Believes the wildcard case may sit anywhere in the list
- Calls `_` an ordinary throwaway name inside a pattern
- Assumes every match statement requires a wildcard case
- Expects a case after `case _:` to be silently dead code
- Thinks a wildcard rejects `None` or empty containers