是否可以在 python 数据类中对变量进行分组?

Posted

技术标签:

【中文标题】是否可以在 python 数据类中对变量进行分组?【英文标题】:Is it possible to group variables in a python dataclass? 【发布时间】:2021-12-02 14:10:16 【问题描述】:

我已经搜索了但没有找到好的答案,所以我会发一个帖子:)

我目前正在创建一个 python 模块,它使用一个 http get 请求来获取一个具有这样结构的一堆数据的对象。

主组 第 1 组 数据1 数据2 第 2 组 数据1 数据2 第 3 组 数据1 数据2

我创建了一个数据类,它只列出了所有这些变量,例如

@dataclass
class MyData:
  grp1_data1: str
  grp1_data2: str
  grp2_data1: str
  grp2_data2: str
  grp3_data1: str
  grp3_data2: str

@classmethod
def from_dict(cls, data: dict) -> "MyData":
    return cls(
      grp1_data1=data["Main group"]["Group 1"]["data1"],
      grp1_data2=data["Main group"]["Group 1"]["data2"],
      # And so on ...
    )

我正在寻找的是一种将数据类中的变量分组的方法,类似于结构,这样我就不需要在变量名中混合组名和数据名。

我对 python 很陌生,我不知道什么样的组功能可以与数据类一起使用,如果有的话?

我希望能够写出类似grp1.data1=data["Main group"]["Group 1"]["data1"] 或类似的东西。

【问题讨论】:

制作两个数据类,一个代表一个组,另一个包含该组数据类的多个实例...? 【参考方案1】:

可以使用类组合创建多级数据类来做你想做的事(可能不如 C 类型的结构优雅,但它可以工作):

@dataclass
class Top:
    
    @dataclass
    class Child:
        data1: str
        data2: str
            
    Group1: Child
    Group2: Child
    Group3: Child
        
        
inst = Top(
    Group1=Top.Child('a','b'),
    Group2=Top.Child('x', 'y'),
    Group3=Top.Child('101', '102')
)

# check it:
@dataclass
class Top:
    
    @dataclass
    class Child:
        data1: str
        data2: str
            
    Group1: Child
    Group2: Child
    Group3: Child
        

# create an instance
inst = Top(
    Group1=Top.Child('a','b'),
    Group2=Top.Child('x', 'y'),
    Group3=Top.Child('101', '102')
)

# check it:
assert inst.Group2.data2 == 'y'

关键是您必须将所有子成员也定义为数据类(或者更准确地说是类)。 您可以就地(如上)或单独定义子类。

【讨论】:

完美,这正是我想要的!谢谢!【参考方案2】:

您的问题有点不清楚,但正如 cmets 中所建议的那样,最好将 single 模型作为代表您的组数据的数据类(即包含 data1data2 fields)并定义一个辅助函数,该函数构造组名到模型实例的映射,如下所示。

注意:这里假设您使用的是 Python 3.8+。对于早期版本,我会做两件事:

如果需要,请删除 __future__ 导入,而是从 typing 模块导入 TypeDict,因为 Python 3.8 或更早版本中的内置类型不支持下标值。 删除 Python 3.8 中引入的 walrus := 运算符的用法,改为使用它后面的注释行。
# Future import to allow the `int | str` syntax below
# Can be removed for Python 3.10
from __future__ import annotations

from dataclasses import dataclass
from typing import TypeVar


# Create a type that can be `MyData`, or any subclass
D = TypeVar('D', bound='MyData')


@dataclass
class MyData:
    data1: str
    data2: str

    @classmethod
    def from_dict(cls: type[D], data: dict, group_num: int | str) -> D:
        return cls(
            data1=data['MG'][f'G group_num']['data1'],
            data2=data['MG'][f'G group_num']['data2'],
        )

    @classmethod
    def group_to_data(cls: type[D], data: dict) -> dict[int, D]:
        return (group_num := int(group_key.split()[-1])): cls.from_dict(
                    data, group_num)
                for group_key in data['MG']

        # For Python 3.7 or lower, uncomment and use the below instead
        # ret_dict = 
        # for group_key in data['MG']:
        #     group_num = int(group_key.split()[-1])
        #     ret_dict[group_num] = cls.from_dict(data, group_num)
        #
        # return ret_dict

测试代码:

def main():
    from pprint import pprint

    my_data = 
        'MG': 
            'G 1': 
                'data1': 'hello',
                'data2': 'World!',
            ,
            'G 2': 
                'data1': '',
                'data2': 'Testing',
            ,
            'G 3': 
                'data1': 'hello 123',
                'data2': 'world 321!'
            
        
    

    group_to_data = MyData.group_to_data(my_data)
    pprint(group_to_data)

    # True
    assert group_to_data[1] == MyData('hello', 'World!')

输出:

1: MyData(data1='hello', data2='World!'),
 2: MyData(data1='', data2='Testing'),
 3: MyData(data1='hello 123', data2='world 321!')

【讨论】:

以上是关于是否可以在 python 数据类中对变量进行分组?的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 ruby​​ on rails 中对关联进行分组?

在 Python 中对嵌套列表进行排序和分组

如何通过在R语言中对相同的变量进行分组来将行合并为单列

如何根据阈值在 Python 中对多列进行分组并创建新列

通过参数传递变量并稍后在类中对其进行修改

如何在 MySQL 中对具有不同平均值的三个变量进行分组?