python - 将类 init 作为列表对象或标准对象

标签 python list class

我必须将数据结构转换为对象。该数据结构可以由任意数量的嵌套列表和字典组成。我已经编写了当前能够执行此操作的代码,只要输入数据是最高级别的字典即可。如果输入数据是列表,那么这将不起作用,因为没有用于创建属性的初始键。如果输入数据是列表,我正在寻找的功能将使此类返回一个列表。

我当前的代码如下:

class DataConverter(object):
    def __init__(self, data):
        if isinstance(data, dict):
            for key in data:
                value = data[key]
                if isinstance(value, list):
                    new_list = []
                    for ind in value:
                        if isinstance(ind, dict):
                            new_list.append(DataConverter(ind))
                        else:
                            new_list.append(ind)
                    setattr(self, key, new_list)
                elif isinstance(value, dict):
                    setattr(self, key, DataConverter(value))
                else:
                    setattr(self, key, value)
        elif isinstance(data, list):
            new_list = []
            for val in data:
                new_list.append(DataConverter(val))
            # TODO: class needs to init as 'new_list' if it gets here

输入数据的结构与此类似,但更大、更深 1000 倍:

input_data = {
    "foo": "bar",
    "x": "y",
    "Something": 12345,
    "other": [
        {
            "yes": 1,
            "no": 0
        }
    ],
}

如果我要转换此数据,我希望像这样使用生成的对象:

>>> converted_data = DataConverter(input_data)
>>> converted_data.other[0].yes
1

当我获得如下结构的数据时,就会出现此问题:

input_data = [
    {
        "foo": "bar",
    },
    {
        "x": "y",
    },
    {
        "Something": 12345,
    },
    {
        "other": [
            {
                "yes": 1,
                "no": 0
            }
        ]
    }
]

我希望这些数据在转换后能够像这样使用:

>>> converted_data = DataConverter(input_data)
>>> converted_data[3].other[0].no
0

我开始编写一些我认为可行的东西,但如果输入是列表,我无法弄清楚如何将 DataConverter 对象初始化为列表对象。

回答

根据 JL Peyret 的回答,我添加了工厂方法并更改了一些代码以制作更好的版本。

class DataConverter(object):
    def __init__(self, input_data):
        if isinstance(input_data, dict):
            for key, data in input_data.items():
                if isinstance(data, dict):
                    setattr(self, key, DataConverter(data))
                elif isinstance(data, list):
                    setattr(self, key, DataConverter.factory(data))
                else:
                    setattr(self, key, data)
    @classmethod
    def factory(cls, data_input):
        if isinstance(data_input, dict):
            return DataConverter(data_input)
        elif isinstance(data_input, list):
            package = []
            for part in package:
                package.append(cls.factory(part))
            return package

现在的预期用途

>>> obj = DataConverter.factory(input_data)
>>> obj[3].other[0].yes
1

最佳答案

我不会尝试对类 __init__ 本身变得太聪明,而是使用工厂方法:

    @classmethod
    def factory(cls, data):
        if isinstance(data, dict):
            return cls(data)
        elif isinstance(data, list):
            res = []
            for part in data:
                res.append(cls(part))
            return res

整个代码:

class DataConverter(object):
    def __init__(self, data):
        if isinstance(data, dict):
            for key in data:
                value = data[key]
                if isinstance(value, list):
                    new_list = []
                    for ind in value:
                        if isinstance(ind, dict):
                            new_list.append(DataConverter(ind))
                        else:
                            new_list.append(ind)
                    setattr(self, key, new_list)
                elif isinstance(value, dict):
                    setattr(self, key, DataConverter(value))
                else:
                    setattr(self, key, value)
        elif isinstance(data, list):
            new_list = []
            for val in data:
                new_list.append(DataConverter(val))
            # TODO: class needs to init as 'new_list' if it gets here

    @classmethod
    def factory(cls, data):
        if isinstance(data, dict):
            return cls(data)
        elif isinstance(data, list):
            res = []
            for part in data:
                res.append(cls(part))
            return res


input_data = {
"foo": "bar",
"x": "y",
"Something": 12345,
"other": [
    {
        "yes": 1,
        "no": 0
    }
],
}





input_data_list = [
        {
            "foo": "bar",
        },
        {
            "x": "y",
        },
        {
            "Something": 12345,
        },
        {
            "other": [
                {
                    "yes": 1,
                    "no": 0
                }
            ]
        }
        ]



converted_data = DataConverter.factory(input_data)
print (f"{converted_data.other[0].yes=}")

converted_data_list = DataConverter.factory(input_data_list)
print(f"{converted_data_list[3].other[0].no=}")

和输出:

converted_data.other[0].yes=1
converted_data_list[3].other[0].no=0

关于python - 将类 init 作为列表对象或标准对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70717661/

相关文章:

Java 初学者 GUI 单选按钮

python - 使用集合中的 Counter 动态创建的字典的总和值

python - 如何将 dynamo 项目从 scan 转换为 dict/json?

r - R中带有列表的两个列表的总和

php - 关闭连接 PDO

Python:数据对象或类

Python strftime 时钟

python - csv.writerows() 在每一行之后放置换行符

c++ - C++ 中的列表<字符串>

java - 在 Java 中创建一个 List<Pair<L,R>> 并支持 .get(key) 方法,就像 map 一样。