現在はDTO(データ転送オブジェクト)をこのように使っています。
class Test1:
def __init__(self,
user_id: int = None,
body: str = None):
self.user_id = user_id
self.body = body
サンプルコードは非常に小さいですが、オブジェクトの規模が大きくなるにつれて、すべての変数を定義する必要があります。
調べてみると、Python 3.7がサポートされていることがわかりましたdataclass
以下のコードは DTO が使用するデータクラスです。
from dataclasses import dataclass
@dataclass
class Test2:
user_id: int
body: str
この場合、定義されていない引数をさらに渡すにはどうすればよいでしょうかclass Test2
?
を使うと簡単Test1
です。**kwargs(asterisk)
__init__
class Test1:
def __init__(self,
user_id: int = None,
body: str = None,
**kwargs):
self.user_id = user_id
self.body = body
しかし、データクラスを使用しても、それを実装する方法が見つかりません。
ここに解決策はあるでしょうか?
ありがとう。
編集
class Test1:
def __init__(self,
user_id: str = None,
body: str = None):
self.user_id = user_id
self.body = body
if __name__ == '__main__':
temp = {'user_id': 'hide', 'body': 'body test'}
t1 = Test1(**temp)
print(t1.__dict__)
結果 :{'user_id': 'hide', 'body': 'body test'}
ご存知のとおり、辞書型のデータを挿入したいのですが ->**temp
データクラスでアスタリスクを使用する理由も同じです。
辞書型をクラス init に渡す必要があります。
何かアイデアはありますか?
ベストアンサー1
データクラスの基本的な使用例は、引数を属性にマップするコンテナーを提供することです。不明な引数がある場合、クラスの作成時にそれぞれの属性を知ることはできません。
初期化中にどの引数が不明であるかがわかっている場合は、手動でキャッチオール属性に送信することで回避できます。
from dataclasses import dataclass, field
@dataclass
class Container:
user_id: int
body: str
meta: field(default_factory=dict)
# usage:
obligatory_args = {'user_id': 1, 'body': 'foo'}
other_args = {'bar': 'baz', 'amount': 10}
c = Container(**obligatory_args, meta=other_args)
print(c.meta['bar']) # prints: 'baz'
しかし、この場合でも、調べる必要がある辞書がまだ存在し、名前で引数にアクセスすることはできませんc.bar
。つまり、機能しません。
名前で属性にアクセスする必要がある場合、または初期化中に既知の引数と未知の引数を区別できない場合は、書き直さずに(そもそも を__init__
使用する目的をほぼ無効にします)、最後の手段として、 を記述します。dataclasses
@classmethod
from dataclasses import dataclass
from inspect import signature
@dataclass
class Container:
user_id: int
body: str
@classmethod
def from_kwargs(cls, **kwargs):
# fetch the constructor's signature
cls_fields = {field for field in signature(cls).parameters}
# split the kwargs into native ones and new ones
native_args, new_args = {}, {}
for name, val in kwargs.items():
if name in cls_fields:
native_args[name] = val
else:
new_args[name] = val
# use the native ones to create the class ...
ret = cls(**native_args)
# ... and add the new ones by hand
for new_name, new_val in new_args.items():
setattr(ret, new_name, new_val)
return ret
使用法:
params = {'user_id': 1, 'body': 'foo', 'bar': 'baz', 'amount': 10}
Container(**params) # still doesn't work, raises a TypeError
c = Container.from_kwargs(**params)
print(c.bar) # prints: 'baz'