Search code examples
pythonstructural-pattern-matching

Why does a match-case statement assign to a variable used in one of the cases if the variable was not previously defined?


While learning pattern matching introduced in Python 10 I came across an example where a part of splitted string was being assigned/bound to a variable used in one of the cases.

match 'make dir'.split():
    case ["make"]:
       print("default make")
    case ["make", cmd]:
       print(f"make command found: {cmd}"}
    case ["restart"]:
       print("restarting")
    case ["rm", *files]:
       print (f"deleting files: {files}")
    case _:
       print("didn't match")

The second case has the previously undeclared variable cmd, which ends up being assigned the value "dir".


Solution

  • In the pattern ["make", cmd], cmd is a capture pattern. Capture patterns (which look like un-dotted names such as foo, bar, or cmd) match anything, and unconditionally bind the matched value to that name.

    In your example, any sequence of length 2 starting with "make" will bind the second element to cmd and execute the second case block. This is useful since it allows your app to easily determine which make command it should execute.

    This happens whether cmd is already assigned or not. So, if it is already bound, that old value will be overwritten with the new, matched value.

    If you want to compare a name by value instead, you have a couple of options depending on your situation:

    • If the name is dotted (like args.cmd or Class.VAR), it will automatically compare by equality (and not capture). So you can just use ["make", args.cmd] as your pattern.

    • If the name is bare (like cmd or VAR), you can use a capture pattern together with a guard to compare by equality. Using this technique, your pattern could look like ["make", c] if c == cmd. Note that since c is a capture pattern, it will be rebound just like cmd in your original example! (As you use pattern matching more, you'll find that capture patterns like c are extremely useful when performing more complex pattern matches.)

    I recommend that anybody looking to familiarize themselves with Python's structural pattern matching check out the official tutorial. It covers all of the different patterns (including capture patterns) in a very easy-to-understand way.