web-dev-qa-db-ja.com

値がclsのインスタンスである場合、戻り値の型に注釈を付けることができますか?

初期化のためのヘルパーメソッドを持つクラスが与えられた場合:

class TrivialClass:
    def __init__(self, str_arg: str):
        self.string_attribute = str_arg

    @classmethod
    def from_int(cls, int_arg: int) -> ?:
        str_arg = str(int_arg)
        return cls(str_arg)

from_intメソッドの戻り値の型に注釈を付けることは可能ですか?

clsTrivialClassの両方を試しましたが、PyCharmはそれらを未解決の参照としてフラグ付けし、その時点で妥当と思われます。

23
Jonatan

generic typeを使用して、clsのインスタンスを返すことを示します。

_from typing import Type, TypeVar

T = TypeVar('T', bound='TrivialClass')

class TrivialClass:
    # ...

    @classmethod
    def from_int(cls: Type[T], int_arg: int) -> T:
        # ...
        return cls(...)
_

クラスメソッドをオーバーライドした後、親クラスTrivialClassまたはまだ祖先であるサブクラス)のインスタンスを返すサブクラスは、ファクトリメソッドはclsタイプのインスタンスを返すように定義されているため、エラーとして検出されます。

bound引数は、TTrivialClass(のサブクラス)でなければならないことを指定します。ジェネリックを定義するときにクラスがまだ存在しないため、 forwardreference (文字列名前)。

PEP 484の インスタンスおよびクラスメソッドへの注釈セクション を参照してください。


注:この回答の最初の改訂では、クラス自体を戻り値として指定する前方参照を使用することを提唱しましたが、 issue 1212 により、代わりにジェネリックを使用できるようになり、より良い解決策になりました。

Python 3.8以降、モジュールを-で開始するときに、アノテーションで前方参照を使用する必要がなくなりますできます_from __future__ import annotations_ ですが、モジュールレベルでTypeVar()オブジェクトを作成することは注釈ではありません。

41
Martijn Pieters

戻り値の型に注釈を付ける簡単な方法は、クラスメソッドの戻り値の注釈として文字列を使用することです。

# test.py
class TrivialClass:
  def __init__(self, str_arg: str) -> None:
    self.string_attribute = str_arg

  @classmethod
  def from_int(cls, int_arg: int) -> 'TrivialClass':
    str_arg = str(int_arg)
    return cls(str_arg)

これはmypy0.560を渡し、Pythonからのエラーはありません。

$ mypy test.py --disallow-untyped-defs --disallow-untyped-calls
$ python test.py
6
Noah Gilmore

Python 3.7から __future__.annotations

from __future__ import annotations


class TrivialClass:
    # ...

    @classmethod
    def from_int(cls, int_arg: int) -> TrivialClass:
        # ...
        return cls(...)

編集:classmethodをオーバーライドせずにTrivialClassをサブクラス化することはできませんが、これが必要ない場合は、前方参照よりも優れていると思います。

2
rusheb