- Slides (Spanish) presented at Pycon Latam 2021.
- PEP 634 - Specification
- PEP 635 - Motivation and Rationale
- PEP 636 - Tutorial
- Changelog Python 3.10
- Paper Dynamic Pattern Matching with Python
Last active
August 28, 2021 17:40
-
-
Save fefi95/2cf2cf5006d211f15df8bd06c070b7bb to your computer and use it in GitHub Desktop.
Pattern Matching in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import List | |
def http_error(status: int) -> str: | |
match status: | |
case 400: | |
return "Bad request" | |
case 404: | |
return "Not found" | |
case 418: | |
return "I'm a teapot" | |
case _: | |
return "Other" | |
# The tails function returns all final segments of | |
# the argument, longest first. For example: | |
# | |
# >>> tails([1,2,3,4]) | |
# [[1, 2, 3, 4], [2, 3, 4], [3, 4], [4]] | |
def tails(initial_list: list) -> List[list]: | |
match initial_list: | |
case []: | |
return [] | |
case [_, *rest] as full_list: | |
return [full_list] + tails(rest) | |
# >>> get_data({"data": 100}) | |
# 100 | |
# | |
# >>> get_data({"other": 2323, "error": "An error msg"}) | |
# Exception: An error msg | |
# | |
# >>> get_data({"error": 400}) | |
# Exception: Bad request (400) | |
def get_data(response: dict): | |
match response: | |
case {"data": data}: | |
return data | |
case {"error": int(code)}: | |
raise Exception(f"{http_error(code)} ({code})") | |
case {"error": str(msg)}: | |
raise Exception(msg) | |
case _: | |
raise Exception("Unknown error") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from dataclasses import dataclass | |
from typing import List, Union | |
class Suit: | |
CLUB = "♣" | |
DIAMOND = "♦" | |
SPADE = "♠" | |
HEART = "♥" | |
class Symbol: | |
ACE = "A" | |
JACK = "J" | |
QUEEN = "Q" | |
KING = "K" | |
@dataclass | |
class Card: | |
suit: Suit | |
symbol: Union[Symbol | int] | |
def evaluate(self) -> int: | |
match self: | |
case Card(_, Symbol.ACE) | Card(Suit.SPADE | Suit.CLUB, Symbol.JACK): | |
return 11 | |
case Card(_, Symbol.JACK) | Card(_, Symbol.QUEEN) | Card(_, Symbol.KING): | |
return 10 | |
case Card(_, int(n)) if n > 1 or n < 11: | |
return n | |
case _: | |
raise Exception("Invalid card") | |
# Use to compare the `case` version with the `if` version | |
def evaluate_with_if(self) -> int: | |
if ( | |
self.symbol == Symbol.ACE | |
or ((self.suit == Suit.SPADE or self.suit == Suit.CLUB) | |
and self.symbol == Symbol.JACK) | |
): | |
return 11 | |
elif ( | |
self.symbol == Symbol.JACK | |
or self.symbol == Symbol.QUEEN | |
or self.symbol == Symbol.KING | |
): | |
return 10 | |
elif type(self.symbol) is int and self.symbol > 1 and self.symbol < 11: | |
return self.symbol | |
else: | |
raise Exception("Invalid card") | |
class BlackJackHand: | |
def __init__(self, cards: List[Card]) -> None: | |
self.cards = cards | |
def eval_hand(self) -> int: | |
aces_count = len([c for c in self.cards if c.symbol == Symbol.ACE]) | |
hand_value = sum([c.evaluate() for c in self.cards]) | |
if aces_count > 0 and hand_value > 21: | |
return hand_value - aces_count * 10 | |
return hand_value | |
if __name__ == "__main__": | |
print( | |
BlackJackHand( | |
[Card(Suit.DIAMOND, Symbol.ACE), Card(Suit.DIAMOND, 2)] | |
).eval_hand() | |
) | |
print( | |
BlackJackHand( | |
[Card(Suit.DIAMOND, Symbol.ACE), Card(Suit.DIAMOND, Symbol.KING)] | |
).eval_hand() | |
) | |
print( | |
BlackJackHand( | |
[Card(Suit.DIAMOND, Symbol.ACE), Card(Suit.SPADE, Symbol.JACK)] | |
).eval_hand() | |
) | |
print( | |
BlackJackHand( | |
[Card(Suit.DIAMOND, Symbol.ACE), Card(Suit.DIAMOND, Symbol.ACE)] | |
).eval_hand() | |
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Exercise: https://www.codewars.com/kata/5a25ac6ac5e284cfbe000111 | |
class Color: | |
RED = "R" | |
GREEN = "G" | |
BLUE = "B" | |
def next_color(color1: str, color2: str) -> Color: | |
colors = (color1, color2) | |
match colors: | |
case (x, y) if x == y: | |
return x | |
case (Color.BLUE, Color.RED) | (Color.RED, Color.BLUE): | |
return Color.GREEN | |
case (Color.GREEN, Color.RED) | (Color.RED, Color.GREEN): | |
return Color.BLUE | |
case (Color.BLUE, Color.GREEN) | (Color.GREEN, Color.BLUE): | |
return Color.RED | |
case _: | |
raise(Exception("Color is not valid")) | |
# Use to compare the `case` version with the `if` version | |
def next_color_with_if(color1: str, color2: str) -> Color: | |
if color1 == color2: | |
return color1 | |
elif (color1 == Color.BLUE and color2 == Color.RED) or ( | |
color1 == Color.RED and color2 == Color.BLUE | |
): | |
return Color.GREEN | |
elif (color1 == Color.GREEN and color2 == Color.RED) or ( | |
color1 == Color.RED and color2 == Color.GREEN | |
): | |
return Color.BLUE | |
elif (color1 == Color.BLUE and color2 == Color.GREEN) or ( | |
color1 == Color.GREEN and color2 == Color.BLUE | |
): | |
return Color.RED | |
raise (Exception("Color is not valid")) | |
def gen_next_row(string: str) -> str: | |
return "".join( | |
[next_color(color1, string[i + 1]) for i, color1 in enumerate(string[:-1])] | |
) | |
def gen_color_triangle(colors: str) -> str: | |
match colors: | |
case "": | |
raise Exception("Invalid input") | |
case x if len(x) == 1: | |
return colors | |
case _: | |
next_row = gen_next_row(colors) | |
return gen_color_triangle(next_row) | |
if __name__ == "__main__": | |
print(gen_color_triangle("GG")) # -> G | |
print(gen_color_triangle("BG")) # -> R | |
print(gen_color_triangle("GR")) # -> B | |
print(gen_color_triangle("RRGBRGBB")) # -> G |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment