目前我使用的DTO(数据传输对象)如下所示。
class Test1:
def __init__(self,
user_id: int = None,
body: str = None):
self.user_id = user_id
self.body = body
示例代码很小,但是当对象规模变大时,我必须定义每个变量。
在深入研究时,发现python3.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。
有什么想法吗?
8条答案
按热度按时间mklgxw1f1#
数据类的基本用例是提供一个将参数Map到属性的容器,如果你有未知的参数,你就不能在类创建过程中知道相应的属性。
如果在初始化过程中知道哪些参数是未知的,可以通过手动将它们发送到一个捕获所有属性来解决这个问题:
但是在这种情况下,您仍然需要查看字典,并且无法通过参数名称访问参数,即
c.bar
不起作用。如果您关心通过名称访问属性,或者在初始化过程中无法区分已知参数和未知参数,那么不重写
__init__
(这几乎完全违背了使用dataclasses
的初衷)的最后一个办法是编写@classmethod
:用法:
tyu7yeag2#
Dataclass只依赖于
__init__
方法,因此您可以自由地在__new__
方法中更改您的类。41ik7eoe3#
这是我用过的一个简洁的变体。
其工作原理如下:
但是,请注意,数据类似乎并不知道它具有这些新属性:
这意味着键必须是已知的。这对我的用例和其他可能的用例都有效。
nkhmeac64#
pwuypxnk5#
answer from Trian Svinit的变化:
您可以使用以下方法:
1.额外属性通过
kwargs
参数添加,如下所示:(x月1日至1x日)kwargs
是一个dataclasses.InitVar
,随后将在数据类的__post_init__
中进行处理1.可以使用
instance.__dict__
访问所有值(因为asdict
不会检测通过kwargs=...
添加的属性这将只使用数据类的原生特性,并且继承该类仍然有效。
如果你真的需要使用
asdict
来获取作为kwargs传递的属性,你可以开始使用dataclass中的私有属性来破解asdict
:5n0oy7gb6#
基于Arnes Answer,我创建了一个类装饰器,它使用from_kwargs方法扩展了数据类装饰器。
oalqel3c7#
所有这些改变都是善意的,但很明显违背了数据类的精神,即避免编写一堆样板文件来设置类。
Python 3.10引入了
match
语句,数据类通过它在构造器(即装饰器)中获得了一个match_args=True
默认参数。这意味着您会得到一个dunder属性
__match_args__
,它存储了init(kw)参数的元组,重要的是没有运行时检查。所以你可以创建一个类方法
它的工作原理是:
然而,由于
__dataclass_fields__
,我们在Python 3.9中也可以访问这些相同的键,如果不能依赖Python 3.10运行时,__dataclass_fields__
是次佳选择。这给出了相同的结果。
对于问题中的用例(不寻常但合理!),您可以在构建
init_kw
dict时将类方法更改为pop
,而不是访问kwargs
dict,这样剩下的键将留在kwargs
中,并可以作为它们自己的kwargrest
传递。请注意,您必须将
kwargs
Package 在对dict
的调用中(进行复制),以避免"dict size changed during iteration"错误mrfwxfqh8#
对于这个问题,应该使用
default_factory
,正如数据类文档中所述。