Coincidencia de patrones estructurados en Python 3.10

La versión de Python 3.10 , cuyo trabajo comenzó el 25 de mayo de 2020, está programado para su lanzamiento el 4 de octubre de 2021 y contendrá una serie de innovaciones interesantes. Una de las innovaciones más prometedoras será la coincidencia de patrones estructurados (coincidencia de patrones estructurados). Para ello, se introducirá una instrucción especial de coincidencia de patronesmatch



. La funcionalidad de coincidencia de patrones sin duda será de interés, especialmente para los programadores de FP, donde juega un papel importante. El resto de novedades de la nueva versión del lenguaje se describen aquí .





Python, a pesar de todo su poder y popularidad, durante mucho tiempo no tuvo la forma de control de flujo que se encuentra en otros lenguajes, una forma de tomar un valor y asignarlo elegantemente a una de las muchas condiciones posibles. En los lenguajes C y C ++, esto se realiza mediante una construcción switch/case



; en Rust y F #, esta construcción se llama coincidencia de patrones.





Las formas tradicionales de hacer esto en Python no son elegantes. Uno de ellos es escribir una cadena de expresiones if/elif/else



. Otra es almacenar valores que coinciden como claves en un diccionario y luego usar los valores por clave para realizar una acción, por ejemplo, almacenar una función como un valor y usar una clave o alguna otra variable como entrada. En muchos casos, estas técnicas funcionan bien, pero son difíciles de diseñar y mantener.





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