是否可以在 python 数据类中对变量进行分组?
Is it possible to group variables in a python dataclass?
我已经搜索过了,但没有找到好的答案,所以我会做一个 post :)
我目前正在创建一个 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"]
或类似的东西。
你的问题有点不清楚,但正如评论中所建议的,最好有一个 single 模型作为代表你的组数据的数据类(即一个模型包含 data1
和 data2
字段)并定义一个辅助函数,该函数构造组名称到模型实例的映射,如下所示。
注意: 这假设您使用的是 Python 3.8+。对于早期版本,我会做两件事:
- 如果需要,删除
__future__
导入,而是从 typing
模块导入 Type
和 Dict
,因为内置类型不支持中的下标值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!')}
可以使用 class 组合创建多级数据classes 来做你想做的事情(可能不像 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'
关键是您必须将所有子成员也定义为数据classes(或者更准确地说是classes)。
您可以就地(如上)或单独定义子 class(es)。
我已经搜索过了,但没有找到好的答案,所以我会做一个 post :)
我目前正在创建一个 python 模块,它使用 http get 请求来获取一个对象,其中包含一堆结构如下的数据。
- 主要群体
- 第 1 组
- 数据1
- 数据2
- 第 2 组
- 数据1
- 数据2
- 第 3 组
- 数据1
- 数据2
- 第 1 组
我创建了一个数据类,它只列出了所有这些变量,例如
@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"]
或类似的东西。
你的问题有点不清楚,但正如评论中所建议的,最好有一个 single 模型作为代表你的组数据的数据类(即一个模型包含 data1
和 data2
字段)并定义一个辅助函数,该函数构造组名称到模型实例的映射,如下所示。
注意: 这假设您使用的是 Python 3.8+。对于早期版本,我会做两件事:
- 如果需要,删除
__future__
导入,而是从typing
模块导入Type
和Dict
,因为内置类型不支持中的下标值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!')}
可以使用 class 组合创建多级数据classes 来做你想做的事情(可能不像 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'
关键是您必须将所有子成员也定义为数据classes(或者更准确地说是classes)。 您可以就地(如上)或单独定义子 class(es)。