0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

dataclassのフィールド名一覧を取得する方法

Last updated at Posted at 2025-05-24

結論

フィールド名一覧を取得する1には、dataclasses.fields を使いましょう。

from typing import ClassVar
from dataclasses import dataclass, fields

@dataclass
class MyDataClass:
    x: int
    y: str
    default_val: str = "hoge"
    classvar_any = 10
    classvar_annotated: ClassVar[int] = "fuga"

all_field_names = [field.name for field in fields(MyDataClass)]
# => ['x', 'y', 'default_val']

Field オブジェクトとして一覧が得られるので .name でアクセスします。

生成AIに「Pythonでdataclassのフィールド名一覧を取得する方法は?」と質問すると結構な確率で __dataclass_fields__ を使うよう回答してくる2のですが、これは公式に用意されたインターフェースではなく3、また dataclasses.fields と微妙に挙動の違いがあり意図しない動作の元になるため、使わない方が良いです。

生成AIの回答例:
より高級なモデルほど __dataclass_fields__ への"こだわり"が薄れていく傾向にあります4

Google の AI 要約

がっつり __dataclass_fields__ の使用を勧めてくる(回による)

image.png
image.png

ChatGPT (o4-mini)

dataclasses.fields__dataclass_fields__ の二択を提示

image.png

ChatGPT (4o)

サブの選択肢として __dataclass_fields__ も提示(どちらの方法でも同じというのは誤り)

image.png

Gemini (2.5 Flush)

__dataclass_fields__ への言及なし

image.png
image.png

挙動の差

__dataclass_fields__ は「型アノテーションをつけたクラス変数」が除外されません。
型アノテーションの有無で挙動が変わるというのはデータ構造として望ましくないので、型アノテーションあり・なしの両方とも除外される dataclass.fields の方が"正常な"挙動といっていいでしょう。

>>> fields(MyDataClass)
(Field(name='x',type=<class 'int'>,default=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), Field(name='y',type=<class 'str'>,default=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), Field(name='default_val',type=<class 'str'>,default='hoge',default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD))
>>> [field.name for field in fields(MyDataClass)]
['x', 'y', 'default_val']
>>>
>>> MyDataClass.__dataclass_fields__
{'x': Field(name='x',type=<class 'int'>,default=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'y': Field(name='y',type=<class 'str'>,default=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'default_val': Field(name='default_val',type=<class 'str'>,default='hoge',default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD), 'classvar_annotated': Field(name='classvar_annotated',type=typing.ClassVar[int],default='fuga',default_factory=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=<dataclasses._MISSING_TYPE object at 0x7f8138fa9e80>,_field_type=_FIELD_CLASSVAR)}
>>> MyDataClass.__dataclass_fields__.keys()
dict_keys(['x', 'y', 'default_val', 'classvar_annotated'])

いかにも dataclass.fields と等価な dunder(特殊メソッド)のような命名の割に中身が違うというのがちょっとした罠ですね。実際には __dataclass_fields__ はアノテーションがついている変数をまとめて保持しておくだけの一時変数であり、fields ではさらに if f._field_type is _FIELD というフィルターでフィールド変数以外を除外する処理が追加されています。

  1. ユースケースとして例えばデータベースから取得したテーブルデータをiterrowsでレコードごとにインスタンス化し、その際にバリデーションしたい場合など。バリデーションをするならPydanticを使ったほうが良いですが。

  2. いくつかの技術ブログで __dataclass_fields__ を使う方法が紹介されているのを学習してしまっているのだと思います。

  3. 公式ドキュメントに記載がなく、実装にも明示的に定義されていません。

  4. 内省ができるモデルは「__ で始まるのはprivateな変数で、特段理由がなければ外部から使うべきものではない」ということをなんとなく推論できているんじゃないかという気がします。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?