LoginSignup
1
1

More than 3 years have passed since last update.

PEP 612 (Parameter Specification Variables) を読んだよメモ

Posted at

Microsoft の Python 向け型チェッカーの pyright の README を流し読みしていたら、初めて聞く PEP が登場したシリーズ第二弾です。
今回は PEP 612 (Parameter Specification Variables) について書きます。

概要

  • 汎用のデコレータを書こうとすると、型を書くのが非常に難しい
  • 指定された関数と同じ引数を持つ関数 を表現する方法がほしい

アプローチ

  • ParameterSpecification という引数を表す型を追加すると解決する

引数を表す型として ParameterSpecification を追加する。
ParameterSpecificationCallable と一緒に用いることで callable object のジェネリクスっぽく振る舞うことができる。 TypeVar の引数版と考えるとわかりやすい。

以下の例では add_logging() の引数は Callable[Ps, R] 型で、返り値も同じく Callable[Ps, R] 型である。つまり、引数として指定された関数と同じインターフェースの関数を返すデコレータである。

そのため、 @add_logging でデコレートされた foo()(x: int, y: str) -> int 型のままである。

from typing import Callable, ParameterSpecification, TypeVar

Ps = ParameterSpecification("Ps")
R = TypeVar("R")

def add_logging(f: Callable[Ps, R]) -> Callable[Ps, R]:
    def inner(*args: Ps.args, **kwargs: Ps.kwargs) -> R:
        log_to_database()
        return f(*args, **kwargs)

    return inner


@add_logging
def foo(x: int, y: str) -> int:
    return x + 7

ParameterSpecification 型が導入されない場合、こういったデコレータに型をつけることは難しい。

感想

  • 幸いなことにこれまでデコレータに型をつけることがなかったので気づかなかったが、確かに ParameterSpecification がないと適切な型がつけられない
  • ParameterSpecification という名前はちょっと長いが、特に代案は思いつかなかったの仕方ない…
  • 引数をいじるタイプのデコレータはこの PEP では扱わないとされているので、全てが解決ではないのが残念
  • まだ Draft なので採用は決まってません
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1