Created
August 17, 2025 10:17
-
-
Save mahenzon/651ef928b6fc3e0aed9ec5a3536e3bc9 to your computer and use it in GitHub Desktop.
Python 3.12 ParamSpec example
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
| import logging | |
| # DEFAULT_LOG_FORMAT = "[%(asctime)s.%(msecs)03d] %(funcName)20s %(module)s:%(lineno)d %(levelname)-8s - %(message)s" | |
| DEFAULT_LOG_FORMAT = ( | |
| "%(funcName)10s %(module)s:%(lineno)d %(levelname)-8s - %(message)s" | |
| ) | |
| def configure_logging(level: int = logging.INFO) -> None: | |
| logging.basicConfig( | |
| level=level, | |
| datefmt="%Y-%m-%d %H:%M:%S", | |
| format=DEFAULT_LOG_FORMAT, | |
| ) |
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
| import logging | |
| import random | |
| from dataclasses import dataclass | |
| from functools import wraps | |
| from typing import Callable, reveal_type | |
| from common import configure_logging | |
| log = logging.getLogger(__name__) | |
| @dataclass | |
| class Counts: | |
| count: int = 0 | |
| def inc(self) -> None: | |
| self.count += 1 | |
| def dec(self) -> None: | |
| self.count -= 1 | |
| def trace[** P, T]( | |
| *, | |
| sep: str = "*", | |
| size: int = 1, | |
| ) -> Callable[[Callable[P, T]], Callable[P, T]]: | |
| def decorator(func: Callable[P, T]) -> Callable[P, T]: | |
| count = Counts() | |
| @wraps(func) | |
| def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: | |
| count.inc() | |
| log.info( | |
| "%s call %r with args %r and kwargs %r", | |
| sep * count.count * size, | |
| func.__name__, | |
| args, | |
| kwargs, | |
| ) | |
| result = func(*args, **kwargs) | |
| log.info( | |
| "%s call %r result: %r", | |
| sep * count.count * size, | |
| func.__name__, | |
| result, | |
| ) | |
| count.dec() | |
| return result | |
| return wrapper | |
| return decorator | |
| @trace() | |
| def fac(n: int) -> int: | |
| if n <= 2: | |
| return n | |
| return n * fac(n - 1) | |
| @trace(sep="|", size=2) | |
| def fib(n: int) -> int: | |
| if n < 2: | |
| return n | |
| return fib(n - 1) + fib(n - 2) | |
| def stringify[** P, T](func: Callable[P, T]) -> Callable[P, str]: | |
| @wraps(func) | |
| def wrapper(*args: P.args, **kwargs: P.kwargs) -> str: | |
| return str(func(*args, **kwargs)) | |
| return wrapper | |
| @stringify | |
| def random_number() -> int: | |
| return random.randint(1, 100) | |
| # @stringify | |
| def square(n: int) -> int: | |
| return n * n | |
| def demo_trace() -> None: | |
| fac5 = fac(5) | |
| log.info("fac(5) = %s", fac5) | |
| log.warning("space") | |
| fac7 = fac(7) | |
| log.info("fac(7) = %s", fac7) | |
| log.warning("space bigger") | |
| fib3 = fib(3) | |
| log.info("fib(3) = %s", fib3) | |
| log.warning("space") | |
| fib4 = fib(4) | |
| log.info("fib(4) = %s", fib4) | |
| def main() -> None: | |
| configure_logging() | |
| # demo_trace() | |
| number = random_number() | |
| reveal_type(number) | |
| sq = square(4) | |
| reveal_type(sq) | |
| if __name__ == "__main__": | |
| main() |
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
| [tool.mypy] | |
| strict = true |
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
| mypy==1.14.1 | |
| mypy-extensions==1.0.0 | |
| typing_extensions==4.12.2 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment