The pattern matching syntax introduced in Python 3.10 allows decision making in applications using powerful new programming techniques.Python, while powerful and popular, has long lacked the kind of process control found in other languages, where a value is matched against multiple possible conditions in an elegant way. In C and C++, this is done by constructing theswitch/case
statement; in Rust, this is called "pattern matching".
In Python, the traditional implementation is not elegant. One way is to write a series of expressions. Another way is to store the values to be matched as keys in a dictionary and then use those values to perform the appropriate operations, such as storing functions as values and using keys or other variables as input. In many cases, this approach can work well, but it can be cumbersome to build and maintain, using theif/elif/else
Statements.
After a number of failed proposals, a recent proposal by Guido van Rossum, the founder of the Python language, and a number of other contributors has been accepted to introduce structured pattern matching in Python 3.10. Structured pattern matching not only performs simple style matching, but also supports a wider range of use cases.
Python Structured Pattern Matching
Structured pattern matching introduces statements and pattern syntax into Python. The statement follows the same pattern as theif/elif/else
A basic overview of the same. It takes an object, tests that object for one or more matching patterns, and performs the appropriate action when a match is found.
match command: case "quit": quit() case "reset": reset() case unknown_command: print (f"Unknown command '{unknown_command}'")
Each statement is followed by a pattern to match. In the example above, we used a simple string as our match target, but more complex matches are possible. In fact, the main use case for structured pattern matching is to match patterns of types, not patterns of values.Python performs matches by traversing the list of cases from top to bottom. On the first match, Python executes the statement in the corresponding block, then jumps to the end of the block and continues with the rest of the program. There is no "cut-through" between cases, but logic can be designed to handle multiple possible situations within a single block. (More on this later.) It is also possible to capture all or part of a match and reuse it. In the example above, if the match is not successful, the value will be "captured" in a variable so that we can reuse it.
Matching variables with Python structural pattern matching
Here's one thing to keep in mind. If a variable name is listed in a statement, this does not mean that the contents of the named variable should be matched. In thecase
statement, the variable is used to capture the value being matched. If you want to match the contents of a variable, then the variable must be represented by a dot-separated name, just like an enumeration. The following is an example:
from enum import Enum class Command(Enum): QUIT = 0 RESET = 1 match command: case : quit() case : reset()
It is not necessary to use an enumeration; any dot-separated property name will do. But enumerations are usually the most familiar and customary way to perform this operation in Python. You cannot match the contents of a variable by index. For example.x[0]
will be rejected as a syntax error.
Matching Multiple Elements with Python Structured Pattern Matching
The key to working most effectively with pattern matching is not just using it as a substitute for dictionary lookups or if/else chains. It is a way of describing the structure to be matched. In this way, matches can be made based on the number of elements to be matched or combinations of them. Here is a slightly more complex example. In this example, the user enters a command, optionally followed by a filename.
command = input("Command:") match (): case ["quit"]: quit() case ["load", filename]: load_from(filename) case ["save", filename]: save_to(filename) case _: print (f"Command '{command}' not understood")
Let's look at each of these in turn:
-
case ["quit"]
: Tests whether we are matching a list containing only one element, the string "quit", obtained by splitting the input. -
case ["load", filename]
: Test if the first split element is the string "load" and if there is a string immediately following it. If so, we store the second string in the variablefilename
in it and use it for further operations. -
case ["save", filename]
: Similar to the above, the first split element is tested to see if it is the string "save" and if there is a string immediately following it. If so, we store the second string in the variablefilename
in it and use it for further operations. -
case _
: This is a wildcard match. It will match if no other matches have been made so far. Note that the underscore variable_
Not actually bound to anything; the name is used as a signal for the command, indicating that the case is a wildcard. (That's why we reference the variable in the body of the block; nothing is captured.)
Matching Patterns for Structural Patterns in Python
Patterns can be simple values or contain more complex matching logic. Here are some examples:
case "a"
: Matches a single value "a".
case ["a","b"]
: Match set ["a", "b"].
case ["a", value1]
: matches a set containing two values and puts the second value into the capture variablevalue1
Center.
case ["a", *values]
: Matches sets containing at least one value. The other values (if any) will be stored in thevalues
in. Note that each collection can contain only one asterisked item (like an asterisked argument in a Python function).
case ("a"|"b"|"c")
: Use of the bracket operator()
Multiple cases can be handled in a single block. Here, we match"a"
、"b"
maybe"c"
。
case ("a"|"b"|"c") as letter
: Similar to the above, except now the matched items are put into the variableletter
Center.
case ["a", value] if
: Match capture only if the expression is true. You can use capture variables in expressions. For example, if we usevalue in valid_values
, then only if the captured value is actually in the setvalid_values
It matches when it is in the middle.
case ["z", _]
: Any set of items starting with "z" will match.
Matching objects using Python structured pattern matching
The most advanced feature of Python's structured pattern matching system is the ability to match against objects with specific attributes. Consider an application where we're working with an object nameddata
object that we want to convert to a file and return from the function.
match media_object: case Image(codec="jpg"): # Return as-is return media_object case Image(codec="png") | Image(codec="gif"): return render_as(media_object, "jpg") case Video(): raise ValueError("Can't extract frames from video yet") case other_type: raise Exception(f"Media object {media_object} of type {codec} can't be handled yet")
In each of these cases, we are looking for objects of a specific type, sometimes with specific attributes. The first case matches objects that have the attributeimage_codec
set to"jpg"
of the object. The second case matches iftype
be"png"
maybe"gif"
. The third case matches any case of typeVideo
of the object, regardless of its properties. The last case is our wildcard case, which will capture all objects if nothing else matches, even though we used an actual name to capture it instead of using the_
. We can also capture in object matching:
match media_object: case Image(codec=media_type): print (f"Image of type {media_type}")
Effective use of Python structural pattern matching
The key to structured pattern matching in Python is to write matches that cover the structural cases to be matched. Simple tests on constants are fine, but if that's all that's being done, then a simple dictionary lookup may be a better choice. The real value of structured pattern matching is the ability to match based on patterns of objects, not just a specific object or set of objects to choose from. Another important thing to remember is the order of matches. Which matches you test first will have an impact on the efficiency and accuracy of the overall match. Most people who have built long chains will realize this, but due to the potential complexity, pattern matching requires you to think more carefully about the order. Put the most specific matches at the top and the most general matches at the end. Finally, if your problem can be solved with a simple chain structure or dictionary lookup, then use it! Pattern matching is powerful, but it's not foolproof. When solving a problem, choose the most appropriate method based on the characteristics of the problem.
to this article on the analysis of how to use structural pattern matching in Python on this article, more related Python structural pattern matching content, please search for my previous posts or continue to browse the following related articles I hope you will support me in the future more!