Initial experience of new features of Python 3.10
Note: picture source
catalogue
- Structural pattern matching [PEP 635]
- union type allows X | Y [PEP 604]
- Parenthesized context manager
1, Structure pattern matching (New) PEP 635)
If you are familiar with other languages, you must know that the switch - > case statement has never had this syntax before Python 3.10, but in this update, version 3.10 + supports this syntax for structural pattern matching - match - > case
1. Basic grammar
match expression: # Condition, which can be any expression or variable case pattern_1: # Pattern, condition to match 1 ... # Code block to execute case pattern_2: # Pattern, condition to match 2 ... # Code block to execute case _: # Mode, indicating default ... # Code block to execute
2. Pattern
1. as mode (AS)
def simplify_expr(tokens): match tokens: case [('(' | '[') as l, *expr, (')' | ']') as r] if (l + r) in ('()', '[]'): # The first parameter must be ('(' | '[') and the alias is l # The last parameter must be ('(' | '[') and the alias is r # And you need to judge that (l + r) in ('()', '[]') is True before entering this code block for execution print(expr) case [0, ('+' | '-') as op, right]: # The first parameter must be 0 # The second parameter must be ('+' | '-'), alias op # The third parameter is any number # The length of the sequence must be 3 print(op, right) case [(int() | float()) as value]: # The length of a sequence can only be 1 # Moreover, the type can only be int or float print(value) case _: # If it doesn't match, go here print("Not matched to") simplify_expr(['(', "aaa", "bbb", ")"]) # ['aaa', 'bbb'] simplify_expr(['[', "aaa", "bbb", "]"]) # ['aaa', 'bbb'] simplify_expr(['[', "aaa", "bbb", ")"]) # Not matched to simplify_expr(['[', "]"]) # [] simplify_expr(['bbb', '[', "]"]) # Not matched to simplify_expr([0, "+", 3]) # + 3 simplify_expr([0, "-", 3]) # - 3 simplify_expr([0, "-", 3, 34]) # Not matched to simplify_expr([1]) # 1 simplify_expr([1.0]) # 1.0 simplify_expr([1.0, 1]) # Not matched to simplify_expr(["aaaa"]) # Not matched to
2. or mode (|)
def demo(code): match code: case 200: print("200 succeed") case 400 | 404: print("Something's wrong") case (1002 | 1006, 200): # Organize two values (organization mode) print("Interface request succeeded") case _: print("Cannot match") demo(200) # 200 succeeded demo(400) # Something's wrong demo(404) # Something's wrong demo((1006, 200)) # Interface request succeeded demo(502) # Cannot match
3. Text mode (Literal)
def simplify(expr): match expr: case ('+', 0, x): return x case ('+' | '-', x, 0): return x case ('and', True, x): return x case ('and', False, x): return False case ('or', False, x): return x case ('or', True, x): return True case ('not', ('not', x)): return x return expr print(simplify(('+', 0, 12))) # 12 print(simplify(('+', 13, 0))) # 13 print(simplify(('-', 13, 0))) # 13 print(simplify(('and', True, 0))) # 0 print(simplify(('and', False, 0))) # False print(simplify(('or', False, 1))) # 1 print(simplify(('or', True, 1))) # True print(simplify(('not', ('not', 23)))) # 23
4. Capture mode (Capture)
def average(*args): match args: case [x, y]: return (x + y) / 2 case [x]: return x case []: return 0 case [x, y, z]: return x + y + z case a: return sum(a) / len(a) print(average(1, 2, 3, 4)) # 2.5 ==> a ==> sum(a) / len(a)==> (1+2+3+4)/4 = 2.5 print(average(1, 2)) # 1.5 ==> [x, y] ==> (x+y)/2 ==> (1+2)/2=1.5 print(average(1)) # 1 ==> [x] ==> x=1 print(average()) # 0 ==> [] ==> 0 # If three elements are passed, they will be matched according to the length, which is different from the dictionary type print(average(1, 2, 3)) # 6 ==> [x, y, z] ==> 1+2+3=6
5. Wildcard pattern (Wildcard)
- _: any character preceded by:
- case: here is at the end, indicating default
def is_closed(sequence): match sequence: case [_]: # A sequence of only one element return True case [start, *_, end]: # A sequence containing at least two elements return start == end case _: # Match any type return False print(is_closed(1)) # False ==> _ ==> False print(is_closed([1])) # True ==> [_] ==> True print(is_closed([1, 2, 3])) # False ==> [start, *_, end] ==>>1 ==3 ==>False
6. Value mode (value)
class HttpStatus(object): OK = 200 MOVED_PERMANENTLY = 301 NOT_FOUND = 404 class MimeType(object): TEXT = "text" APPL_ZIP = "appl_zip" def handle_reply(reply): match reply: case (HttpStatus.OK, MimeType.TEXT, body): print(f"Request succeeded, type is TEXT,body==>{body}") case (HttpStatus.OK, MimeType.APPL_ZIP, body): print(f"Request succeeded, type is APPL_ZIP,body==>{body}") case (HttpStatus.MOVED_PERMANENTLY, new_URI): print(f"301 OK, check it quickly URI==>{new_URI}") case (HttpStatus.NOT_FOUND): print("Website hung up...") handle_reply([200, "text", "dddddd"]) # The request is successful. The type is text, body = = > dddd handle_reply([200, "appl_zip", "dddddd"]) # The request is successful. The type is appl_zip, body = = > dddd handle_reply([200, "appl_zip", "dddddd"]) # The request is successful. The type is appl_zip, body = = > dddd handle_reply([301, "sip:smith@zte.com.cn"]) # 301, check the URI = = > SIP: smith@zte.com.cn handle_reply(404) # Website hung up...
7. Organizational model (Group)
Implementation using or mode
def demo(code): match code: case 200: print("200 succeed") case 400 | 404: print("Something's wrong") case (1002 | 1006, 200): # Organize two values (organization mode) print("Interface request succeeded") case _: print("Cannot match") demo((1006, 200)) # Interface request succeeded
8. Sequence
def is_closed(sequence): match sequence: case [_]: # A sequence of only one element return True case [start, *_, end]: # A sequence containing at least two elements return start == end case _: # Match any type return False print(is_closed(1)) # False ==> _ ==> False print(is_closed([1])) # True ==> [_] ==> True print(is_closed([1, 2, 3])) # False ==> [start, *_, end] ==>>1 ==3 ==>False
9. Mapping mode
def change_red_to_blue(json_obj): match json_obj: case {'color': ('red' | '#FF0000')}: json_obj['color'] = 'blue' case {'children': children}: for child in children: change_red_to_blue(child) color = {"color": "red"} print(color) # {'color': 'red'} change_red_to_blue(color) print(color) # {'color': 'blue'} # Note: if the transfer parameter is a dictionary, match it from the bottom. As long as it is matched, it will not be matched from the bottom # As follows, color contains two keys: color and children. When matching, the matching ends when color is matched, and the next step of matching children will not be carried out color = {"color": "red", "children": [{"color": "#FF0000"}]} print(color) # {'color': 'red', 'children': [{'color': '#FF0000'}]} change_red_to_blue(color) print(color) # {'color': 'blue', 'children': [{'color': '#The color in FF0000'}]} children will not be modified
10. Class mode (Class)
class MyClassA(object): def __init__(self, name) -> None: self.name = name def demo(class_): match class_: case MyClassA(name="desire"): print("yes desire ah") case _: print(class_.name) demo(MyClassA("ronin")) # ronin ==> _ ==> MyClassA("ronin").name ==> class_.name=ronin demo(MyClassA("desire")) # Yes, yes = = > myclassa (name = "yes") = = > Print ("yes, yes")
3. Match the order to be noted
- When the match object is a list or tuple, it needs to match the length and element value to hit. It is reflected in the capture mode.
- When the match object is a dict, the rules are different. As long as the key in the case expression exists in the match object, it can be hit, which is reflected in the mapping mode.
- When the match object is a class object, the matching rule is a bit similar to dict. As long as the object type and object attributes meet the case conditions, they can be hit, which is reflected in the class pattern.
2, The union type allows X | Y( PEP 604)
The new syntax union accepts function, variable, and parameter annotations.
1. Simple grammar
# before from typing import List, Union, Optional def f(list: List[Union[int, str]], param: Optional[int]) -> Union[float, str]: pass # now is more concise from typing import List def f(list: List[int | str], param: int | None) -> float | str: pass
2. typing.Union and | are equivalent
int | str == typing.Union[int, str] # True
3. The order is not required
(int | str) == (str | int) # True (int | str | float) == typing.Union[str, float, int] # True
4. isinstance and issubclass support
isinstance(5, int | str) # True isinstance("aaa", int | str) # True isinstance(1.22, int | str) # False issubclass(bool, int | float) # True isinstance(None, int | None) # True isinstance(42, None | int) # True
3, Parenthesized context manager
The use of outer parentheses has been supported to enable multiple context managers to write multiple lines in succession. This allows an overly long set of context managers to be formatted as multiple lines in a similar manner to previous import statements.
The following four formats are supported
# Previous formats do not affect usage with open("readme.md", 'r') as f: pass with (open("readme.md", 'r') as f): pass with (open("readme.md", 'r') as f1, open("readme.md", 'r') as f2): pass with (open("readme.md", 'r'), open("readme.md", 'r') as f2): pass with (open("readme.md", 'r'), open("readme.md", 'r'), ): pass