1
1

More than 1 year has passed since last update.

dataclassの初期値を動的に入れる

Last updated at Posted at 2023-08-25

とりあえず

dataclassは好きです。型指定あんま役に立たないけど

でも、初期値が面倒です。特に
dataclasses.field(default_factory・・・
これ

そんなわけで、なんとかしたいと思います

@dataclasses.dataclass
class Margin:
    top: int
    bottom: int
    left: int
    right: int
    al: list

@dataclasses.dataclass
class Color:
    r: int
    g: int
    b: int
    m: Margin

@dataclasses.dataclass
class Config:
    margin : Margin
    output_margin : Margin
    corner_average : float
    threshold_gray : int
    threshold_color : Color

こんなdataclassを作りました。dataclass内で他のdataclassを参照してたりして、色々アレです。

そして、こうです

DefaultInitializer = {int: 0, float:0.0, str:'', list:[], dict:{}}

def DCinitializer(DataClass: type, initializer: dict = DefaultInitializer, **kwargs):
    arg = {}
    for k, attr in DataClass.__annotations__.items():
        f = False
        for at, dv in initializer.items():
            if attr is at:
                f = True
                arg[k] = dv
        for kw, dv in kwargs.items():
            if kw == k:
                f = True
                arg[k] = dv
        if not f:
            sarg = {}
            for kw, dv in kwargs.items():
                if k == kw[:len(k)]:
                    sarg[kw[len(k)+1:]] = dv
            arg[k] = DCinitializer(attr,**sarg)
    return DataClass(**arg)

a = DCinitializer(Config,margin_top = 5)
print(a)
#結果
#Config(margin=Margin(top=5, bottom=0, left=0, right=0, al=[]),
#     output_margin=Margin(top=0, bottom=0, left=0, right=0, al=[]),
#     corner_average=0.0, threshold_gray=0,
#     threshold_color=Color(r=0, g=0, b=0, 
#     m=Margin(top=0, bottom=0, left=0, right=0, al=[])))
#

それぞれの型の初期値は
DefaultInitializer = {int: 0, float:0.0, str:'', list:[], dict:{}}
で決めています。dataclassがネストしていても、遡ってそれぞれの値を入れます
クラスの初期値は別の方が良いとかなら
DefaultInitializer = {int: 0, float:0.0, str:'', list:[], dict:{}}, Margin:(10,10,10,10,['ほげ'])
とでも入れておけばそのクラスの初期値はそれになります

a = DCinitializer(Config,margin_top = 5)
の、margin_top = 5は
クラス指定されているmarginのtopプロパティが対象です
本当は
a = DCinitializer(Config,margin.top = 5)
と書きたかったのですが、それだとSyntaxErrorが出てしまうので_にしています。別に_で無くてもPythonで変数と認識してくれるものならなんでもいいです

初期値の引数はキーワード引数で無いといけませんが、素のdataclassのように全部書かなくても必要な部分だけで構いません

とりあえず思いつきで作ったので、あんまり細かい事は考えてませんが、使えるかもしれません

###追記
fix typo by @shiracamus
ご指摘ありがとうございます。

initializerの綴り間違ってた・・・

コメント欄でのご指摘もありがとうございます。短くなって良いですね

1
1
1

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