web-dev-qa-db-ja.com

どうすればPython 3.7の新しいデータクラスフィールドタイプを取得できますか?

Python 3.7には、データクラスと呼ばれる新しい機能が導入されています。

from dataclasses import dataclass

@dataclass
class MyClass:
    id: int = 0
    name: str = ''

関数パラメーターで型ヒント(注釈)を使用する場合、inspectモジュールを使用して注釈付きの型を簡単に取得できます。データクラスフィールドタイプを取得するにはどうすればよいですか?

17
Kamyar
from dataclasses import dataclass

@dataclass
class MyClass:
    id: int = 0
    name: str = '' 

myclass = MyClass()

myclass.__annotations__
>> {'id': int, 'name': str}
myclass.__dataclass_fields__
>> {'id': Field(name='id',type=<class 'int'>,default=0,default_factory=<dataclasses._MISSING_TYPE object at 0x0000000004EED668>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD),
 'name': Field(name='name',type=<class 'str'>,default='',default_factory=<dataclasses._MISSING_TYPE object at 0x0000000004EED668>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),_field_type=_FIELD)}

サイドノートにもあります:

myclass.__dataclass_params__
>>_DataclassParams(init=True,repr=True,eq=True,order=False,unsafe_hash=False,frozen=False)
10
Serbitar

__annotations__を調べると生の注釈が得られますが、それらは必ずしもデータクラスのフィールドタイプに対応するとは限りません。 ClassVarやInitVarなどは、フィールドではありませんが、__annotations__に表示され、継承されたフィールドは表示されません。

代わりに、データクラスで dataclasses.fields を呼び出し、フィールドオブジェクトを検査します。

field_types = {field.name: field.type for field in fields(MyClass)}

__annotations__fieldsも文字列注釈を解決しません。文字列注釈を解決したい場合、おそらく最良の方法は typing.get_type_hints です。 get_type_hintsにはClassVarsとInitVarsが含まれるので、fieldsを使用してこれらを除外します。

resolved_hints = typing.get_type_hints(MyClass)
field_names = [field.name for field in fields(MyClass)]
resolved_field_types = {name: resolved_hints[name] for name in field_names}
14
user2357112

dataclasses.py は、フィールド注釈を使用して通常のクラスメソッドを生成するためのデコレーターと関数を提供するモジュールです。これは、クラスを処理した後、ユーザー定義フィールドが PEP 526構文の変数注釈 を使用して形成されることを意味します。モジュールの注釈には、__annotations__としてアクセスできます。

型注釈の実行時効果 によると、注釈付きの型は、__annotations__属性を介して、または typing.get_type_hints の使用によりアクセスできます。

以下のコードサンプルをご覧ください。

from typing import Dict, ClassVar, get_type_hints
from dataclasses import dataclass

@dataclass
class Starship:
    hitpoints: int = 50


get_type_hints(Starship) // {'hitpoints': int}
Starship.__annotations__ // {'hitpoints': int}
dataclasses.__annotations__ // The annotations of the dataclasses module.
get_type_hints(get_type_hints)
1
Andriy Ivaneyko