带有** kwargs(星号)的python3数据类 [英] python3 dataclass with **kwargs(asterisk)

查看:224
本文介绍了带有** kwargs(星号)的python3数据类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我像这样使用DTO(数据传输对象).

Currently I used DTO(Data Transfer Object) like this.

class Test1:
    def __init__(self, 
        user_id: int = None,
        body: str = None):
        self.user_id = user_id
        self.body = body

示例代码很小,但是当对象规模增长时,我必须定义每个变量.

Example code is very small, But when object scale growing up, I have to define every variable.

在深入研究时,发现python 3.7支持dataclass

While digging into it, found that python 3.7 supported dataclass

下面的代码是DTO使用的数据类.

Below code is DTO used dataclass.

from dataclasses import dataclass


@dataclass
class Test2:
    user_id: int
    body: str

在这种情况下,如何允许将未定义的更多参数传递给class Test2?

In this case, How can I allow pass more argument that does not define into class Test2?

如果我使用Test1,这很容易.只需将**kwargs(asterisk)添加到__init__

If I used Test1, it is easy. Just add **kwargs(asterisk) into __init__

class Test1:
    def __init__(self, 
        user_id: int = None,
        body: str = None,
        **kwargs):
        self.user_id = user_id
        self.body = body

但是使用数据类,找不到实现它的任何方法.

But using dataclass, Can't found any way to implement it.

这里有什么解决办法吗?

Is there any solution here?

谢谢.

编辑

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

As you know, I want to insert data with dictionary type -> **temp

在数据类中使用星号的原因相同.

Reason to using asterisk in dataclass is the same.

我必须将字典类型传递给init类.

I have to pass dictinary type to class init.

这里有什么主意吗?

推荐答案

数据类的基本用例是提供一个将参数映射到属性的容器.如果您有未知的参数,则在类创建过程中将不知道各自的属性.

The basic use case for dataclasses is to provide a container that maps arguments to attributes. If you have unknown arguments, you can't know the respective attributes during class creation.

如果您在初始化期间知道哪些参数未知,可以手动解决该问题,方法是将其手动发送给一个包罗万象的属性:

You can work around it if you know during initialization which arguments are unknown by sending them to a catch-all attribute by hand:

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不起作用.

But in this case you'll still have a dictionary you need to look into and can't access the arguments by their name, i.e. c.bar doesn't work.

如果您关心按名称访问属性,或者在初始化期间无法区分已知参数和未知参数,那么您最后的选择就是不重写__init__(这在很大程度上违反了使用dataclasses的目的)第一名)正在写@classmethod:

If you care about accessing attributes by name, or if you can't distinguish between known and unknown arguments during initialisation, then your last resort without rewriting __init__ (which pretty much defeats the purpose of using dataclasses in the first place) is writing a @classmethod:

@dataclass
class Container:
    user_id: int
    body: str

    @classmethod
    def from_kwargs(cls, **kwargs):

        # split the kwargs into native ones and new ones
        native_args, new_args = {}, {}
        for name, val in kwargs.items():
            if name in cls.__annotations__:
                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

# usage:
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数据类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆