☘️

Pythonの@typing.overrideの役割と使い方

に公開

役割

子クラスが親クラスのメソッドをオーバーライドしている場合、親クラス側でそのメソッドが変更されると、子クラス側も同様に修正が必要になります。しかし従来の仕組みではその関係を型チェッカーが検知できませんでした。そこで、この問題を解決するためにPython3.12で@typing.override(以下、@override)が導入されました。

@overrideを使うことで、親メソッドとメソッド名が異なる場合やシグネチャが異なる場合に自動で検知できます。(実は@overrideがなくても検知できるケースもあるので後述します。)

使い方

基本例

親クラスのメソッドをオーバーライドしているメソッドにデコレーターとして追加するだけです。

from typing_extensions import override


class Base:
    ...
    
    def show(self, num: int):
        print(num)


class Sub(Base):
    ...

    @override
    def show(self, num: int):
        print(num * 2)


if __name__ == "__main__":
    sub = Sub()
    sub.show(2)
% mypy .
Success: no issues found in 1 source file

関数名が異なるケース

ここで、ある人が以下のようにBaseクラスのshowメソッドのメソッド名をdisplayに変更したとします。

class Base:
    ...
    
    def display(self, num: int):
        print(num)

型チェックを実行すると以下のように検出することができます。

% mypy .           
example.py:14: error: Method "show" is marked as an override, but no base method was found with this name  [misc]
Found 1 error in 1 file (checked 1 source file)

ここで試しに子クラスの@overrideをコメントアウトしてみます。
この場合、Subクラスのshowメソッドはオーバーライドではなく新しいクラスの定義と解釈されるため、特にエラーが出ることはありません。

class Sub(Base):
    ...
    
    # @override
    def show(self, num: int):
        print(num * 2)
% mypy .
Success: no issues found in 1 source file

無事(?)検出されなくなりました。

関数のシグネチャが異なるケース

続いて先ほどの関数名を下に戻した上で、引数numの型をintからstrへ変更してみます。

class Base:
    ...
    
    def show(self, num: str):
        return num
% mypy .
example.py:14: error: Argument 1 of "show" is incompatible with supertype "Base"; supertype defines the argument type as "str"  [override]
(中略)
Found 1 error in 1 file (checked 1 source file)

検知できています。
こちらでも@overrideをコメントアウトしてみると、結果は以下のようになります。

% mypy .
example.py:17: error: Argument 1 of "show" is incompatible with supertype "Base"; supertype defines the argument type as "str"  [override]
(中略)
Found 1 error in 1 file (checked 1 source file)

なぜかきちんと検知できています。
実はmypy側でオーバーライドしているかをチェックして、親クラスと子クラスのメソッドのシグネチャに差分があるときは検出してくれるようになっています。

さいごに

mypyなどの型チェックツールである程度よしなにやってくれてるとはいえ、以下の理由で依然として@overrideを使うメリットはあるのかなと思います。

  • 親にそのメソッドが本当に存在するかを保証できる
  • 可読性が上がる

参考文献

https://peps.python.org/pep-0698/
https://docs.python.org/3/library/typing.html#typing.override

Discussion