-
-
Save jstasiak/7f1687100ec7b2000b5206a537b1a0b0 to your computer and use it in GitHub Desktop.
Python enum pattern matching draft
This file contains hidden or 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
| WebEvent.PageLoad | |
| Page loaded | |
| WebEvent.KeyPress('x') | |
| Pressed key x | |
| WebEvent.Click(x=1, y=3) | |
| Clicked on 1/3 | |
| Option.Something('admin') | |
| admin | |
| False | |
| True | |
| Option.Nothing | |
| Can not unwrap | |
| True | |
| False |
This file contains hidden or 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 get_type_hints, TypedDict, get_origin, get_args | |
| def enum(cls): | |
| hints = get_type_hints(cls) | |
| names_values = [(name, getattr(cls, name)) for name in dir(cls)] | |
| for name, value in names_values: | |
| if isinstance(value, type) and hasattr(value, '__annotations__'): | |
| replacement = type(f"{cls.__name__}.{name}", (cls,), {"__annotations__": value.__annotations__}) | |
| replacement = dataclass(replacement) | |
| setattr(cls, name, replacement) | |
| for name, type_ in hints.items(): | |
| if type_ is type(None): | |
| local_name = name | |
| class Singleton(cls): | |
| def __repr__(self): | |
| return f"{cls.__name__}.{local_name}" | |
| replacement = Singleton() | |
| elif get_origin(type_) is tuple: | |
| args = get_args(type_) | |
| parameter_count = len(args) | |
| def __repr__(self): | |
| content = ", ".join(repr(getattr(self, f"param{i}")) for i in range(parameter_count)) | |
| return f"{cls.__name__}.{name}({content})" | |
| replacement = type(f"{cls.__name__}.{name}", (cls,), {"__annotations__": {f"param{i}": t for (i, t) in enumerate(args)}, "__repr__": __repr__}) | |
| replacement = dataclass(replacement) | |
| else: | |
| raise AssertionError(f"Unsupported type: {type_}") | |
| setattr(cls, name, replacement) | |
| return cls | |
| @enum | |
| class WebEvent: | |
| PageLoad: None | |
| KeyPress: tuple[str] | |
| class Click: | |
| x: int | |
| y: int | |
| def inspect(event: WebEvent) -> None: | |
| match event: | |
| case WebEvent.PageLoad: | |
| print("Page loaded") | |
| case WebEvent.KeyPress(c): | |
| print(f"Pressed key {c}") | |
| case WebEvent.Click(x=x, y=y): | |
| print(f"Clicked on {x}/{y}") | |
| print(WebEvent.PageLoad) | |
| inspect(WebEvent.PageLoad) | |
| print(WebEvent.KeyPress("x")) | |
| inspect(WebEvent.KeyPress("x")) | |
| print(WebEvent.Click(x=1, y=3)) | |
| inspect(WebEvent.Click(x=1, y=3)) | |
| print() | |
| print() | |
| from typing import Generic, TypeVar | |
| T = TypeVar("T") | |
| @enum | |
| class Option(Generic[T]): | |
| Nothing: None | |
| Something: tuple[T] | |
| def is_nothing(self): | |
| return self is Option.Nothing | |
| def is_something(self): | |
| return isinstance(self, Option.Something) | |
| def unwrap(self): | |
| if isinstance(self, Option.Something): | |
| return self.param0 | |
| raise RuntimeError(f"Can't unwrap {self}") | |
| def return_user_maybe(condition: bool) -> Option["str"]: | |
| if condition: | |
| return Option.Something("admin") | |
| else: | |
| return Option.Nothing | |
| user = return_user_maybe(True) | |
| print(user) | |
| print(user.unwrap()) | |
| print(user.is_nothing()) | |
| print(user.is_something()) | |
| user = Option.Nothing | |
| print(user) | |
| try: | |
| print(user.unwrap()) | |
| except RuntimeError: | |
| print("Can not unwrap") | |
| print(user.is_nothing()) | |
| print(user.is_something()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment