目前我像这样使用了 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。
这里有什么想法吗?
最佳答案
数据类的基本用例是提供一个将参数映射到属性的容器。如果您有未知参数,则在创建类时无法知道各自的属性。
如果您在初始化期间知道哪些参数是未知的,则可以通过手动将它们发送到 catch-all 属性来解决这个问题:
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
的目的)的最后手段是编写 0x251343124 :from dataclasses import dataclass
from typing import ClassVar
@dataclass
class Container:
user_id: int
body: str
@classmethod
def from_kwargs(cls, **kwargs):
# identify the constructor's signature
cls_fields = {
name for
name, f in cls.__dataclass_fields__.items() if
f.type != ClassVar and getattr(f.type, "__origin__", None) != ClassVar
}
# 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'
关于带有**kwargs(星号)的python3数据类,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/55099243/