This example is being discussed as likely "gotcha" when using pattern matching:
NOT_FOUND = 400
retcode = 200
match retcode:
case NOT_FOUND:
print('not found')
print(f'Current value of {NOT_FOUND=}')
This is an example of accidental capture with structural pattern matching. It gives this unexpected output:
not found
Current value of NOT_FOUND=200
This same problem comes up in other guises:
match x:
case int():
pass
case float() | Decimal():
x = round(x)
case str:
x = int(x)
In this example, str
needs to have parentheses, str()
. Without them, it "captures" and the str builtin type is replaced with the value of x.
Is there a defensive programming practice that can help avoid these problems and provide early detection?
Is there a defensive programming practice that can help avoid these problems and provide early detection?
Yes. Accidental captures are easily detected by always including what PEP 634 describes as an irrefutable case block.
In plain language, that means a catchall case that always matches.
Accidental captures always match. No more than one irrefutable case block is permitted. Therefore, accidental captures are detected immediately when an intentional catchall is added.
Just add a catchall wildcard pattern to the end:
match retcode:
case NOT_FOUND:
print('not found')
case _:
pass
That detects the problem immediately an gives the following error:
SyntaxError: name capture 'NOT_FOUND' makes remaining patterns unreachable
Add a catchall wildcard pattern to the end:
match x:
case int():
pass
case float() | Decimal():
x = round(x)
case str:
x = int(x)
case _:
pass
Again the problem is detected immediately:
SyntaxError: name capture 'str' makes remaining patterns unreachable