1. はじめに
この問題集は、Pythonの基礎を習得した後、次の段階へ進みたい人のサポートをすることが目的です。
また、競技プログラミングとは異なり、複雑なアルゴリズムの問題ではなく「可読性の最大化」に焦点を当てた問題が中心となります。
目次
前の問題:整数?実数?
次の問題:型に厳密なデータクラス2
2. 問題
"""
No.4 型に厳密なデータクラス1
次のSampleデータクラスにはvalueという属性があり、float型を指定しています。
しかし、Sampleクラスの利用者から次のような要望が出てきました。
全ての要望及び制約を満たすようにSampleクラスの改修案を検討してください。
なお、データクラスの使用は必須ではありません。
また、value属性への再代入に関しては、この問題では考慮する必要はありません。
初期値の指定に関してだけ考慮すればよいです。
1. Sample(value='abc')はエラーを発生させたい
指定された値がfloat型へ変換できない場合はエラーを発生させてほしいです。
データクラスの型には強制力がないため、型チェックで警告は出るものの実行できてしまいます。
2. Sample(value=0)やSample(value='0.0')は許容したい
指定された値がfloat型へ変換できる場合は許容したいです。
この場合、Sample(value=0).valueは0ではなく0.0に、
Sample(value='0.0').valueは'0.0'ではなく0.0にしてください。
制約
* Sampleクラスはvalueという属性を持ち、初期値を与えることができる。
"""
from dataclasses import dataclass
@dataclass
class Sample:
value: float
3. 解答例
from dataclasses import dataclass
@dataclass
class Sample:
value: float
def __post_init__(self) -> None:
self.value = float(self.value)
from pydantic import BaseModel
class Sample(BaseModel):
value: float
4. 採点基準
-
float
型へ変換できる場合、value
属性に変換した値が格納されること -
float
型へ変換できない場合、エラーが発生すること
5. 解説
5.1 データクラスを使用する場合
データクラスでは、__post_init__
メソッドを使用することで初期化後の処理を記述することができます。
Python3.7以上のデータ格納はdataclassを活用しよう - Qiita
この中でvalue
属性をfloat
型へ変換し、結果をself.value
に再代入することで、変換可能な場合は処理が続行され、変換不可能な場合はエラーが発生します。
5.2 pydanticを使用する場合
データクラスは便利ですが、属性の型を記述しても強制力が無いのが難点でした。
一方pydantic
というライブラリでは、データクラスと似た文法を維持しつつ、属性の型に強制力を持たせることが可能になっています。
pydanticを使って実行時にも型情報が適用されるPythonコードを書く - Qiita
解答例のように記述するだけで、value
属性に値が格納される際、自動的にfloat
型へ変換されます。
自分で変換処理を書く必要が無いので、シンプルな記述が可能になります。
この他にも便利なバリデーション機能が豊富なので、是非試してみてください。
注意点として、pydantic v1
とpydantic v2
で大きく文法が変更されています。
古い情報を見ると、現在では非推奨の書き方が紹介されていることがあるので注意してください。
(見分けるポイントとしては、@validator
という記述があればv1、@field_validator
や@model_validator
という記述があればv2です。)
6. テストコード
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)
<class 'ValueError'>
could not convert string to float: 'abc'
<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