PEP 636 - Structural Pattern Matching discusses how pattern matching binds values to variables declared on the go:
match command.split(): case ["quit"]: print("Goodbye!") quit_game() case ["look"]: current_room.describe() case ["get", obj]: character.get(obj, current_room)
A pattern like
["get", obj]
will match only 2-element sequences that have a first element equal to "get". It will also bindobj = subject[1]
.
If obj
already had a value, we might expect the value to be used as if it was a literal, but that doesn't happen. Instead obj
is overwritten:
>>> # I'm using Python 3.12. You can copy/paste this straight into iPython
>>> obj = 3
>>> for i in range(5):
... match i:
... case obj:
... print(i) # Does this print only 3?
0
1
2
3
4
>>> obj
4
This doesn't happen if you specify an instance attribute:
>>> from dataclasses import dataclass
>>> @dataclass
... class Num:
... x: int
...
>>> num = Num(x=3)
>>> for i in range(5):
... match i:
... case num.x: # does this bind num.x to i???
... print(i)
...
3
In this second case, num.x
is unchanged and is used as if it were a literal.
This isn't mentioned anywhere in PEP 636 that I can see. Where can I read about this subtlety? Was this behaviour introduced after PEP 636 was implemented?
(Note: I think this behaviour is perfectly sensible and good. I'd just like to know if/where it's documented)
This is specified in the Capture Patterns section of the documentation of match
:
capture_pattern ::= !'_' NAME
NAME
is just a single identifier, so num.x
is not included in this syntax. !'_'
excludes the special case of _
, which is defined as a wildcard pattern in the next section.