Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding accidental capture in structural pattern matching

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?

like image 315
Raymond Hettinger Avatar asked May 13 '21 20:05

Raymond Hettinger


People also ask

What is __ Match_args __?

__match_args__ allows to define a default order for arguments to be matched in when a custom class is used in a case. built-in Python classes can be used in case statements to validate types.

What is structural matching?

Structural pattern matching introduces the match/case statement and the pattern syntax to Python. The match/case statement follows the same basic outline as switch/case . It takes an object, tests the object against one or more match patterns, and takes an action if it finds a match.

Which are the keywords used in structural pattern matching in Python?

Python Structural Pattern Matching — Basic Syntax The whole thing is based on two keywords: match — The subject you want to evaluate conditions for. It could be a status code returned by an API request. case — An individual condition evaluated to see if a match is confirmed.

What is pattern matching explain with example?

Pattern matching is the process of checking whether a specific sequence of characters/tokens/data exists among the given data. Regular programming languages make use of regular expressions (regex) for pattern matching.


1 Answers

Best practice

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.

How it works

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.

Fixing the first example

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

Fixing the second example

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
like image 196
Raymond Hettinger Avatar answered Sep 28 '22 09:09

Raymond Hettinger