任意のdataclass
のインスタンスを受け入れる関数があります。そのための適切なタイプのヒントは何でしょうか?
pythonドキュメントで公式なものが見つかりませんでした
これは私がやってきたことですが、私はそれが正しいとは思いません
from typing import Any, NewType
DataClass = NewType('DataClass', Any)
def foo(obj: DataClass):
...
別のアイデアは、これらのクラス属性__dataclass_fields__
、__dataclass_params__
で Protocol
を使用することです。
その名前にもかかわらず、dataclasses.dataclass
はクラスインターフェイスを公開しません。これにより、カスタムクラスを便利な方法で宣言できるため、データコンテナとして使用されることが明確になります。したがって、理論的には、データクラスは実際には単なる通常のクラスであるため、データクラスでのみ機能するものを作成する機会はほとんどありません。
実際には、とにかくデータクラスのみの関数を宣言したい理由はいくつかあります。それを実現するには2つの方法があります。
静的型チェッカーを使用してプロトコルを作成するright方法
from dataclasses import dataclass
from typing import Dict
from typing_extensions import Protocol
class IsDataclass(Protocol):
# as already noted in comments, checking for this attribute is currently
# the most reliable way to ascertain that something is a dataclass
__dataclass_fields__: Dict
def dataclass_only(x: IsDataclass):
... # do something that only makes sense with a dataclass
@dataclass
class A:
pass
dataclass_only(A()) # a static type check should show that this line is fine
このアプローチは、あなたが質問でほのめかしたものでもありますが、3つの欠点があります。
mypy
などのサードパーティライブラリが必要です。typing_extensions
同様に、Protocol
はまだコアtyping
モジュールの一部ではないためもう少し [〜#〜] eafp [〜#〜] -実際に機能するインスピレーション
from dataclasses import is_dataclass
def dataclass_only(x):
"""Do something that only makes sense with a dataclass.
Raises:
ValueError if something that is not a dataclass is passed.
... more documentation ...
"""
if not is_dataclass(x):
raise ValueError(f"'{x.__class__.__name__}' is not a dataclass!")
...
このアプローチでは、ドキュメントのおかげで、このコードのメンテナーまたはユーザーにとって動作は依然として非常に明確です。ただし、欠点は、コードの静的分析(IDEによるタイプヒントを含む)が得られないことです。