Successfully reported this slideshow.
Your SlideShare is downloading. ×

Structural Pattern Matching in Python

Upcoming SlideShare
Unit Testing in Python
Unit Testing in Python
Loading in …3
×

Check these out next

1 of 35 Ad
1 of 35 Ad

Structural Pattern Matching in Python

Download to read offline

We captured on video the professional meetup we delivered about Structural Pattern Matching. You can find detailed information about that meetup at https://www.meetup.com/lifemichael/events/287980811/

We captured on video the professional meetup we delivered about Structural Pattern Matching. You can find detailed information about that meetup at https://www.meetup.com/lifemichael/events/287980811/

Advertisement
Advertisement

More Related Content

Advertisement

Structural Pattern Matching in Python

  1. 1. Structural Pattern Matching Haim Michael September 20th , 2022 All logos, trade marks and brand names used in this presentation belong to the respective owners. https://youtu.be/xgRYrs_jy5E life michael
  2. 2. © 2021 Haim Michael All Rights Reserved 2 Introduction  As of Python 3.10 we can use patterns matching. There are three PEPs (Python Enhancement Proposals) describing this feature: PEP 634: The Specification https://www.python.org/dev/peps/pep-0634 PEP 635: Motivation and Rationale https://www.python.org/dev/peps/pep-0635 PEP 636: Patterns Matching Tutorial https://www.python.org/dev/peps/pep-0636
  3. 3. © 2021 Haim Michael All Rights Reserved 3 Switch Statement on Steroids  We can consider patterns matching as a switch statement on steroids.
  4. 4. © 2021 Haim Michael All Rights Reserved 4 Matching Specific Values  The simplest form of patterns matching in Python would be a simple use case similar to switch statement. command = "+" match command: case '+': print('plus...') case '-': print('minus') case '*': print('multiply') case '/': print('divide')
  5. 5. © 2021 Haim Michael All Rights Reserved 5 The _ Wildcard  We can use the _ character as a wild card. We shall place the wild card as the last case possibility. If none of the other cases matches, the wild card will. command = "%" match command: case '+': print('plus...') case '-': print('minus') case '/': print('divide') case _: print('soething else')
  6. 6. © 2021 Haim Michael All Rights Reserved 6 Matching Sequences  We can match a sequence with possible sequences composed of literals or variables. operation = ("deposit",1200,123222) operation = ("transfer",800,123222,101888) match operation: case operation,sum,account_id: print("%s %f %d" % (operation,sum,account_id)) case operation, sum, from_id, to_id: print("%s %f from %d to %d" % (operation, sum, from_id, to_id))
  7. 7. © 2021 Haim Michael All Rights Reserved 7 Matching Sequences operation = ["playing","pacman"] match operation: case ["eat",food]: print("eating %s is great" % (food,)) case ["watching",show]: print("enjoy watching %s" % (show,)) case ["playing",game]: print("playing %s is awesome" % (game,)) case _: print("your operation cannot be recognized")
  8. 8. © 2021 Haim Michael All Rights Reserved 8 Matching Multiple Values  We can use the packing capability similarly to the way we use it in assignments.
  9. 9. © 2021 Haim Michael All Rights Reserved 9 Matching Multiple Values operation = ("delete","Hello.py","Calcu.py","Demo.py") match operation: case "delete",*files: print("the following files will be deleted:") for file in files: print(file) case "makedir",*directories: print("the following directories will be created:") for directory in directories: print(directory) case _: print("the requesed operation is not recognized")
  10. 10. © 2021 Haim Michael All Rights Reserved 10 Composing Patters  We can compose new patterns composed from others. Patterns that don't include other patterns can be any of the following: capture patterns, literal patterns, and the wildcard pattern _.
  11. 11. © 2021 Haim Michael All Rights Reserved 11 Composing Patters operation = ("update_mark",("mosh",234234),103444,88) match operation: case "register_course",student,course_id: print("registering to course") print(student) print(course_id) case "update_mark",(student_name,student_id),course_id,mark: print("updating mark in specific course") print("student name: %s", student_name) print("student id: %d" % (student_id,)) print("course id: %d" % (course_id,)) print("mark: %.2f" % (mark,))
  12. 12. © 2021 Haim Michael All Rights Reserved 12 Or Patterns  We can use the | operator (AKA the or operator) in order to create a case that includes more than one pattern. Matching any of the patterns will be considered as matching the entire case.
  13. 13. © 2021 Haim Michael All Rights Reserved 13 Or Patterns command = ("del","temp.txt") match command: case ("delete",file) | ("remove",file) | ("del",file): print("deleting file %s" % (file,)) case ("copy",file,newfile): print("copying file %s to %s" % (file,newfile))
  14. 14. © 2021 Haim Michael All Rights Reserved 14 The as Pattern  We can use the or operator for creating a sub pattern composed of multiple possibilities. We can use the as pattern for finding which is the exact possibility that match.
  15. 15. © 2021 Haim Michael All Rights Reserved 15 The as Pattern data = ("del","temp.txt") match data: case (("delete" | "remove" | "del") as command, file): print("deleting file %s" % (file,)) print("command=%s" % (command,)) case ("copy",file,newfile): print("copying file %s to %s" % (file,newfile))
  16. 16. © 2021 Haim Michael All Rights Reserved 16 Adding Conditions  We can add a condition to specific cases. The condition includes the use of the if keyword followed by expression that its value is of the type bool.
  17. 17. © 2021 Haim Michael All Rights Reserved 17 Adding Conditions data = ("del","temp.txt") files = ["readme.txt", "temp.txt", "index.txt"] match data: case (("delete" | "remove" | "del") as command, file) if file in files: print("deleting file %s" % (file,)) print("command=%s" % (command,)) case (("delete" | "remove" | "del") as command, file) if file not in files: print("the file %s cannot be deleted" % file) case ("copy",file,newfile): print("copying file %s to %s" % (file,newfile))
  18. 18. © 2021 Haim Michael All Rights Reserved 18 Matching Objects Types  When having an object we need to examine its type and its attributes we can avoid the use of isinstance() and we can avoid checking its attributes.
  19. 19. © 2021 Haim Michael All Rights Reserved 19 Matching Objects Types class Dog: def hau(self): return "hau hau" class Cat: def __init__(self,predator): self.predator = predator def miaou(self): return "miaou miaou" class Cow: def moo(self): return "moo moo" ob = Cat(True)
  20. 20. © 2021 Haim Michael All Rights Reserved 20 Matching Objects Types match ob: case Dog(): print(ob.hau()) case Cat(predator=False): print(ob.miaou()) case Cat(predator=True): print("%s grrrrr" % ob.miaou()) case Cow(): print(ob.moo())
  21. 21. © 2021 Haim Michael All Rights Reserved 21 Matching Attributes By Position  When using objects that were instantiated from a class marked as dataclass we can describe the matched attributes by position.
  22. 22. © 2021 Haim Michael All Rights Reserved 22 Matching Attributes By Position from dataclasses import dataclass from math import pow, sqrt @dataclass class Point: x: int y: int @dataclass class Line: p1: Point p2: Point ob = Line(Point(3, 4), Point(6, 8)) match ob: case Line(p1, p2): print(sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2))) case Point(x, y): print(sqrt(pow(x, 2) + pow(y, 2)))
  23. 23. © 2021 Haim Michael All Rights Reserved 23 The __match_args__ Attribute  When using objects that were not instantiated from a class marked as dataclass and were not instantiated from the tuple type we can still describe the matched attributes by position if we add the __match_args__ attribute to the class definition.  The __match_args__ special attribute defines an explicit order for the attributes.
  24. 24. © 2021 Haim Michael All Rights Reserved 24 The __match_args__ Attribute from math import pow, sqrt class Point: __match_args__ = ("x", "y") def __init__(self, x, y): self.x = x self.y = y class Line: __match_args__ = ("p1", "p2") def __init__(self, p1, p2): self.p1 = p1 self.p2 = p2 ob = Line(Point(3, 4), Point(6, 8))
  25. 25. © 2021 Haim Michael All Rights Reserved 25 The __match_args__ Attribute match ob: case Line(p1, p2): print(sqrt(pow(p2.x - p1.x, 2) + pow(p2.y - p1.y, 2))) case Point(x, y): print(sqrt(pow(x, 2) + pow(y, 2)))
  26. 26. © 2021 Haim Michael All Rights Reserved 26 Enums Matching  We can match agains possible values that were defined as part of an Enum object. from enum import Enum class Color(Enum): BLUE = 1 GREEN = 2 RED = 3 BLACK = 4 WHITE = 5 class Car: __match_args__ = ("brand", "id", "color") def __init__(self, brand, id, color): self.brand = brand self.id = id self.color = color
  27. 27. © 2021 Haim Michael All Rights Reserved 27 Enums Matching ob = Car("Mazda 6", 2342343, Color.GREEN) match ob: case Car(car_brand, car_id, Color.WHITE): print("white cars are simpler to handle") case Car(car_brand, car_id, Color.BLACK): print("black cars aborb the heat") case Car(car_brand, car_id, _): print("colorful cars are more fun")
  28. 28. © 2021 Haim Michael All Rights Reserved 28 Mappings Matching  We can match an expression against a dict object. The matching will be based on the keys.
  29. 29. © 2021 Haim Michael All Rights Reserved 29 Mappings Matching  We can match an expression against a dict object. The matching will be based on the keys. command = { 'action': 'getbalance', 'account': { 'accountid': 204714, 'owners_ids': (24537564, 51634545) }}
  30. 30. © 2021 Haim Michael All Rights Reserved 30 Mappings Matching match command: case {'action': 'getbalance', 'account': account}: print("getting balance") print("account id: %s" % (account['accountid'],)) print("account owners are:") print(account['owners_ids']) case {'action': 'deposit', 'sum': sum, 'account': account}: print("deposit %f" % sum) print("account id: %s" % (account,)) print("account owners are:") print(account['owners_ids'])
  31. 31. © 2021 Haim Michael All Rights Reserved 31 Mappings Matching  We can use the dict packing capability when matching a dict object with additional key value pairs that don't match any of the pattern's parts. command = { 'action': 'getbalance', 'account': { 'accountid': 204714, 'owners_ids': (24537564, 51634545) }, 'date': {'day':12,'month':1,'year':1980}, 'time': {'hour': 14, 'minutes': 20} }
  32. 32. © 2021 Haim Michael All Rights Reserved 32 Mappings Matching match command: case {'action': 'getbalance', 'account': account, **ob}: print("getting balance") print("account id: %s" % (account['accountid'],)) print("account owners are:") print(account['owners_ids']) print(ob) case {'action': 'deposit', 'sum': sum, 'account': account, **ob}: print("deposit %f" % sum) print("account id: %s" % (account,)) print("account owners are:") print(account['owners_ids']) print(ob)
  33. 33. Matching Builtin Types  We can use builtin types for validating the types of specific parts in the expression we check. data = { 'action': 'getbalance', 'sum':800, 'account': { 'accountid': 204714, 'owners_ids': (24537564, 51634545) } }
  34. 34. Matching Builtin Types match data: case {'action': str() as action, 'account': account}: print(action) print("account id: %s" % (account['accountid'],)) print("account owners are:") print(account['owners_ids']) case _: print(data)
  35. 35. © 2021 Haim Michael All Rights Reserved 35 Questions & Answers Thanks for Your Time! Haim Michael haim.michael@lifemichael.com +972+3+3726013 ext:700 life michael

×