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?

【Python実践自作問題集】No.5 型に厳密なデータクラス2

Last updated at Posted at 2025-06-07

1. はじめに

この問題集は、Pythonの基礎を習得した後、次の段階へ進みたい人のサポートをすることが目的です。
また、競技プログラミングとは異なり、複雑なアルゴリズムの問題ではなく「可読性の最大化」に焦点を当てた問題が中心となります。

目次
前の問題:型に厳密なデータクラス1
次の問題:型に厳密なデータクラス3

2. 問題

Question
"""
No.5 型に厳密なデータクラス2

次のSampleデータクラスにはvalueという属性があり、float型を指定しています。
また、__post_init__を活用することでvalue属性の値はfloat型に制限されています。
しかし、Sampleクラスの利用者から次のような要望が出てきました。
全ての要望及び制約を満たすようにSampleクラスの改修案を検討してください。

なお、データクラスの使用は必須ではありません。

1. 再代入したときにも型をチェックしたい
    sample = Sample(value=0.0)
    sample.value = 'abc'
    というように、再代入したときにも型をチェックしたいです。
    __post_init__はオブジェクト作成時にしか実行されないため、型チェックが実行されません。
    なお再代入時の型チェックロジックは、初期値を指定するときと同じものを使用してください。

制約
    * Sampleクラスはvalueという属性を持ち、初期値を与えることができる。
    * value属性の初期値にfloat型へ変換できる値が指定された場合、変換後の値をvalue属性に格納する。
    * value属性の初期値にfloat型へ変換できない値が指定された場合、エラーを発生させる。
"""

from dataclasses import dataclass


@dataclass
class Sample:
    value: float

    def __post_init__(self) -> None:
        self.value = float(self.value)

3. 解答例

from pydantic import BaseModel, ConfigDict


class Sample(BaseModel):
    model_config = ConfigDict(validate_assignment=True)

    value: float

4. 採点基準

  • 初期値がfloat型へ変換できる場合、value属性に変換した値が格納されること
  • 初期値がfloat型へ変換できない場合、エラーが発生すること
  • 再代入する値がfloat型へ変換できる場合、value属性に変換した値が格納されること
  • 再代入する値がfloat型へ変換できない場合、エラーが発生すること

5. 解説

前問の類題です。
今回の問題では、再代入する際にも型チェックをするという条件が追加されています。

5.1 pydanticを使用する場合

まずはpydanticを使用した場合ですが、解答の通りmodel_config = ...という1行を追加するだけでOKです。

Pydantic 忘備録 - Qiita

このmodel_config変数をConfigDictで上書きすることで、型チェックの挙動を変更することができます。
型の指定を厳密にするstrictなど、他にも色々なオプションがあるので是非調べてみてください。

Configuration - docs.pydantic.dev

なお、挙動の変更についてもpydantic v1pydantic v2で文法が変更されています。
次のようなConfigクラスを定義する方法は現在非推奨となっているので注意してください。

from pydantic import BaseModel


class Sample(BaseModel):
   value: float

   class Config:
       validate_assignment = True

FastAPIがPydantic v2対応したので、V2移行のポイントを紹介する(意外と簡単) - Zenn

5.2 データクラスを使用する場合

さて、pydanticを使った解答は前節の通りですが、データクラスを使った場合はどうなるのでしょうか?
一応、次のようにして実現はできますが……

from dataclasses import dataclass
from typing import Any


@dataclass
class Sample:
    value: float

    def __setattr__(self, key: str, value: Any) -> None:
        if key == 'value':
            value = float(value)
        super().__setattr__(key, value)

この方法には良くない点があります。
属性valueの名前を変更する場合を考えてみましょう。
最近のエディタは変数名の一括置換ができるものが多いですが、このときif key == 'value''value'までは置換されません。
変更漏れに気付かなければエラーになってしまいます。
また、これは個人的な感覚になってしまいますが、__setattr__のオーバーライドは黒魔術と化しやすい印象を持っています。
そのため、この方法は非推奨としたいと思います。
(もしかしたら別の良い方法があるかもしれません)

6. テストコード

print('-----初期化-----')

value = 0.0
sample = Sample(value=value)
assert sample.value == 0.0
assert isinstance(sample.value, float)

value = 0
sample = Sample(value=value)
assert sample.value == 0.0
assert isinstance(sample.value, float)

value = '0.0'
sample = Sample(value=value)
assert sample.value == 0.0
assert isinstance(sample.value, float)

value = 'abc'
try:
    _ = Sample(value=value)
except (Exception,) as e:
    print(type(e))
    print(e)

print('-----再代入-----')

sample = Sample(value=0.0)
new_value = 1.0
sample.value = new_value
assert sample.value == 1.0
assert isinstance(sample.value, float)

sample = Sample(value=0.0)
new_value = 1
sample.value = new_value
assert sample.value == 1.0
assert isinstance(sample.value, float)

sample = Sample(value=0.0)
new_value = '1.0'
sample.value = new_value
assert sample.value == 1.0
assert isinstance(sample.value, float)

sample = Sample(value=0.0)
new_value = 'abc'
try:
    sample.value = new_value
except (Exception,) as e:
    print(type(e))
    print(e)
実行結果
-----初期化-----
<class 'pydantic_core._pydantic_core.ValidationError'>
1 validation error for Sample
value
  Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='abc', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/float_parsing
-----再代入-----
<class 'pydantic_core._pydantic_core.ValidationError'>
1 validation error for Sample
value
  Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='abc', input_type=str]
    For further information visit https://errors.pydantic.dev/2.11/v/float_parsing
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?