Upgrade to Pro — share decks privately, control downloads, hide ads and more …

こんなこともできる最近の Python の型ヒント

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

こんなこともできる最近の Python の型ヒント

こんなこともできる最近の Python の型ヒント 〜 Python 3.10+ の typing からピックアップ 〜

2026/9/26 鯱.py × Unagi.py コラボイベント in 豊橋 https://shachi-py.connpass.com/event/403190/

Avatar for Yusuke Miyazaki

Yusuke Miyazaki

September 26, 2026

More Decks by Yusuke Miyazaki

Other Decks in Programming

Transcript

  1. def find_user(users: list[User], name: str) -> User | None: ...

    int list[str] TypeVar dict[str, int] X | None T
  2. log def log(func): def wrapper(*args, **kwargs): print(func.__name__) return func(*args, **kwargs)

    return wrapper @log def greet(name, times): for i in range(times): print(f"Hello, {name}!") greet("Shachi", 2) # greet ← @log デコレータが print # Hello, Shachi! ← greet が print # Hello, Shachi! ← greet が print
  3. log from collections.abc import Callable from typing import Any, TypeVar

    R = TypeVar("R") def log(func: Callable[..., R]) -> Callable[..., R]: def wrapper(*args: Any, **kwargs: Any) -> R: print(func.__name__) return func(*args, **kwargs) return wrapper @log def greet(name: str, times: int) -> None: ... greet(3, "Shachi") reveal_type(greet) ... Any # 型エラーにならない # def (*Any, **Any) -> None
  4. ParamSpec from collections.abc import Callable from typing import ParamSpec, TypeVar

    P = ParamSpec("P") R = TypeVar("R") def log(func: Callable[P, R]) -> Callable[P, R]: def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: print(func.__name__) return func(*args, **kwargs) return wrapper
  5. ParamSpec @log def greet(name: str, times: int) -> None: ...

    reveal_type(greet) greet("Shachi", 3) greet(3, "Shachi") # def (name: str, times: int) -> None # OK # 型エラー Callable[..., R] (name: str, times: int)
  6. from collections.abc import Callable # TypeVar や ParamSpec を import

    して、P や R を事前に定義しなくて良い def log[R, **P](func: Callable[P, R]) -> Callable[P, R]: def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: print(func.__name__) return func(*args, **kwargs) return wrapper
  7. rotate def rotate(x): return (*x[1:], x[0]) rotate((1, 2, 3, 4,

    5)) # (2, 3, 4, 5, 1) rotate(("Toyohashi", 123, True)) # (123, True, "Toyohashi")
  8. rotate from typing import Any, TypeVar, overload T1 = TypeVar("T1");

    T2 = TypeVar("T2"); T3 = TypeVar("T3") @overload def rotate(x: tuple[T1, T2]) -> tuple[T2, T1]: ... @overload def rotate(x: tuple[T1, T2, T3]) -> tuple[T2, T3, T1]: ... # ... 要素数ごとに書き続ける @overload def rotate(x: tuple[Any, ...]) -> tuple[Any, ...]: ... TypeVar @overload tuple[Any, ...]
  9. TypeVarTuple *args from typing import TypeVar, TypeVarTuple T = TypeVar("T")

    Ts = TypeVarTuple("Ts") def rotate(x: tuple[T, *Ts]) -> tuple[*Ts, T]: return (*x[1:], x[0]) x: tuple[str, int, bool] = ("Toyohashi", 123, True) y = rotate(x) reveal_type(y) # tuple[int, bool, str]
  10. kwargs def connect(**kwargs): host = kwargs["host"] port = kwargs["port"] ssl

    = kwargs.get("ssl", False) ... connect(host="localhost", port=80) connect(host="localhost", port=443, ssl=True)
  11. kwargs def connect(**kwargs: Any) -> None: ... connect(host="localhost", port=80) #

    OK connect(host=1234, port=80) # おかしな値を渡しても型チェッカーで検出できない connect(unknown="option") # 存在しないオプションを与えても検出できない
  12. TypedDict Unpack **kwargs TypedDict **kwargs Unpack from typing import NotRequired,

    TypedDict, Unpack class ConnectOptions(TypedDict): host: str port: int ssl: NotRequired[bool] def connect(**kwargs: Unpack[ConnectOptions]) -> None: ...
  13. **kwargs connect(host="localhost", port=80) # OK connect(host=1234, port=80) # 型エラー: host

    は str connect(host="localhost", port=80, unknown="option") # 型エラー: 存在しないオプション connect(host="localhost") # 型エラー: 必須の port がない **kwargs: Any
  14. T : 1つの型 **P : 引数列 *Ts : 型の並び Unpack[TypedDict]

    : **kwargs のキーごとの型 **kwargs typing_extensions