Correspondência de padrões estruturados em Python 3.10

A versão do Python 3.10 , cujo trabalho começou em 25 de maio de 2020, está programado para lançamento em 4 de outubro de 2021 e conterá uma série de inovações interessantes. Uma das inovações mais promissoras será o casamento de padrões estruturados (casamento de padrões estruturados). Para isso, uma instrução especial de correspondência de padrões será introduzida match



. A funcionalidade de correspondência de padrões será, sem dúvida, de interesse, especialmente para programadores de FP, onde desempenha um papel importante. As demais novidades da nova versão da linguagem são descritas aqui .





Python, com todo o seu poder e popularidade, por muito tempo não teve a forma de controle de fluxo encontrada em outras linguagens - uma maneira de pegar um valor e mapeá-lo elegantemente para uma das muitas condições possíveis. Nas linguagens C e C ++, isso é feito por uma construção switch/case



; em Rust e F #, essa construção é chamada de correspondência de padrões.





As maneiras tradicionais de fazer isso em Python não são elegantes. Um deles é escrever uma cadeia de expressões if/elif/else



. Outra é armazenar valores que são correspondidos como chaves em um dicionário e, em seguida, usar os valores por chave para realizar uma ação - por exemplo, armazenar uma função como um valor e usar uma chave ou alguma outra variável como entrada. Em muitos casos, essas técnicas funcionam bem, mas são difíceis de projetar e manter.





Python , switch/case



, Python 3.10 Python : . switch/case



, .









  • Python





























Python

Python match/case



. match/case



, switch/case



. , , .





match command:
    case "quit":
        quit()
    case "reset":
        reset()
    case unknown_command:
        print (f"  '{unknown_command}')
      
      



case



, . .





Python , . Python case



, match



. case



«», case



( ).





. case



, unknown_command



, «» unknown_command, .





. case



, , . case



, .





, , . :





from enum import Enum

class Command(Enum):
    QUIT = 0
    RESET = 1

match command:
    case Command.QUIT:
        quit()
    case Command.RESET:
        reset()
      
      



; . , , , Python.





, , , , . , , , .





. , .





command = input()

match command.split():
    case [""]:
        quit()
    case ["", filename]:
        load_from(filename)
    case ["", filename]:
        save_to(filename)
    case _:
        print (f"  '{command}'")
      
      



case



:





case [""]:



, , ""



, .





case ["", filename]:



, ""



, . , filename



. case ["", filename]:



.





case _:



. , . , _



; _



match



, () ( command



case



; .)





, . :





case "a":



"a"



.





case ["a","b"]:



["a","b"]



.





case ["a", value1]:



, value1



.





case ["a", *values]:



, , . , , . , ( Python).





case ("a"|"b"|"c"):



(|



) , case



case



. "a"



, "b"



, "c"



.





case ("a"|"b"|"c") as letter:



, , letter



.





case ["a", value] if <>:



, . . , if



valid_values



, case



, .





case ["z", _]:



, "z"



.





Python , . , media_object



.jpg .





match media_object:
    case Image(type="jpg"):
        #   
        return media_object
    case Image(type="png") | Image(type="gif"):
        return render_as(media_object, "jpg")
    case Video():
        raise ValueError("     ")
    case other_type:
        raise Exception(f"  {media_object}  ")
      
      



case



, . case



Image



, "jpg"



. case



, "png"



"gif"



. case



, Video



, . case



, .





:





match media_object:
    case Image(type=media_type):
        print (f"   {media_type}")
      
      



Python , , . , , , . , .





, . , , . , if/elif/else



, , - . , - .





, if/elif/else



— ! , . , .





:





  • switch/case





# : 
#       
#  Python  3.10.

#   switch/case
def match_errno(errno):
    match errno:
        case 0:
            pass
        case 1:
            pass
        case 42:
            print("42!")
        case _:    #    
            print(" ")
      
      







#     
def command_split(command):
    match command.split():
        case ["make"]:
            print("make  ")
        case ["make", cmd]:
            print(f"  make: {cmd}")
        case ["restart"]:
            print(" ")
        case ["rm", *files]:
            print(f" : {files}")
        case _:
            print("  ")
      
      



  • (|)





#         (|)
def match_alternatives(command):
    match command.split():
        case [""] | [" ", ""]:
            print("   ")
        case ["", obj] | ["", " ", obj] | ["", obj, " "]:
            print(f" : {obj}")
      
      



  • as





#         as
def match_capture_subpattern(command):
    match command.split():
        case [" ", ("" | "" | "" | "") as direction]:
            print(f"   {direction}")
      
      



  • if





#        if
def match_guard(command, exits):
    match command.split():
        case [" ", direction] if direction in exits:
            print(f"   {direction}")
        case [" ", _]:
            print(f"     ")
      
      







#   
from dataclasses import dataclass

@dataclass
class Click:
    position: tuple[int, int]
    button: str

@dataclass
class KeyPress:
    key_name: str

@dataclass
class Quit:
    pass

def match_by_class(event):
    match event:
        case Click(position=(x,y), button="left"):
            print(f"    {x,y}")
        case Click(position=(x,y)):
            print(f"    {x,y}")
        case KeyPress("Q"|"q") | Quit():
            print("  ")
        case KeyPress(key_name="up arrow"):
            print(" ")
        case KeyPress():
            pass #    
        case other_event:
            raise ValueError(f' : {other_event}')
      
      







#   
def match_json_event(event):
    match event:
        case {"transport": "http"}:
            print(" insecure  ")
        case {"verb": "GET", "page": "articles", "pageno": n}:
            print(f"     {n}...")
        case {"verb": "POST", "page": "signup"}:
            print("   ")
      
      



:





def main():
    # x, y = 1, 2
    command_split("make")
    command_split("make clean")
    command_split("restart")
    command_split("rm a b c")
    command_split("doesnt match")
    match_errno(42)
    match_alternatives("go north")
    match_alternatives("pick up sword")
    match_capture_subpattern("go north")
    match_capture_subpattern("go east")
    match_guard("go north", exits=["east", "south"])
    match_guard("go north", exits=["north"])
    match_by_class(Click(position=(0,0), button="left"))
    match_by_class(Quit())

    try:
        match_by_class("BADVALUE")
    except ValueError:
        pass

    match_json_event({"verb": "GET", "page": "articles", "pageno": 5, "info": "extra"})
    pass

if name == 'main':     
    main()
      
      



. . Github , . «» . . , - .








All Articles