Python3.10での構造化パターンマッチング

2020年5月25日に開始されたPython3.10のバージョンは、2021年10月4日のリリースが予定されており、多くの興味深いイノベーションが含まれています。最も有望なイノベーションの1つは、構造化パターンマッチング(構造化パターンマッチング)です。このために、特別なパターンマッチング命令 が導入されmatch



ます。パターンマッチング機能は、特にFPプログラマーにとって、間違いなく興味深いものであり、重要な役割を果たします。新しいバージョンの言語のその他の新規性については、ここで説明します





Pythonは、そのすべての能力と人気のために、長い間、他の言語で見られるフロー制御の形式を持っていませんでした-値を取得し、それを多くの可能な条件の1つにエレガントにマッピングする方法。CおよびC ++言語では、これは構成によって行われswitch/case



ます。RustとF#では、この構成はパターンマッチングと呼ばれます。





Pythonでこれを行う従来の方法は、エレガントではありません。それらの1つは、式のチェーンを作成することですif/elif/else



もう1つは、キーとして一致する値を辞書に保存し、キーごとに値を使用してアクションを実行することです。たとえば、関数を値として保存し、キーまたはその他の変数を入力として使用します。多くの場合、これらの手法はうまく機能しますが、設計と保守が面倒です。





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