使用 JSON 在 Python 中创建类对象的最佳方法

青葱年少 python 215

原文标题Best way to use a JSON to create class objects in Python

我一直在练习使用 JSON 文件和 OOP,所以我想我会同时做这两个,但我一直在努力寻找基于 JSON 部分创建类对象的最有效方法。经过大量询问后,我发现最好的方法是使用**,即使一个字面上不知道它是如何工作的。代码是:

import json

class Warship(object):
    def __init__(self, name, gun_config, top_speed, belt_armor, displacement):
        self.name = name
        self.gun_config = gun_config
        self.top_speed = top_speed
        self.belt_armor =belt_armor
        self.displacement = displacement
    
    def __repr__(self):
        return f'''{self.name}, {self.gun_config}, {self.top_speed} knts, {self.belt_armor} mm, {self.displacement} tons'''


workfile = json.load(open('warships.json', 'r'))

bisc = Warship(**workfile['kms'][0])
tirp = Warship(**workfile['kms'][1])
nc = Warship(**workfile['usn'][0])
wa = Warship(**workfile['usn'][1])

这是我为这个练习制作的 JSON 文件:

{
    "kms": [
        {
            "name": "Bismarck",
            "gun_config": "3x2",
            "top_speed": "29",
            "belt_armor": "320",
            "displacement": "41700"
        },
        {
            "name": "Tirpitz",
            "gun_config": "3x2",
            "top_speed": "30",
            "belt_armor": "320",
            "displacement": "41700"
        }
    ],
    "usn": [
        {
            "name": "North Carolina",
            "gun_config": "3x3",
            "top_speed": "28",
            "belt_armor": "305",
            "displacement": "36600"
        },
        {
            "name": "Washington",
            "gun_config": "3x3",
            "top_speed": "29",
            "belt_armor": "305",
            "displacement": "36600"
        }
    ]
    
}

使用 ** 这样的方式是基于 JSON 对象创建 Python 类对象的最佳方式还是有更好的方式?

原文链接:https://stackoverflow.com//questions/71462500/best-way-to-use-a-json-to-create-class-objects-in-python

回复

我来回复
  • Grismar的头像
    Grismar 评论

    使用**操作符可能是首选的方法,只要您的构造函数参数与您的 JSON 属性的名称完全匹配(就像它们在您的示例中所做的那样)并且只要构造函数上没有可能造成严重破坏的其他参数:

    def Message:
        def __init__(greeting: str, wipe_c_drive: bool = False):
            self.greeting = greeting
            if wipe_c_drive:
                shutil.rmtree('C:/')
    
    
    workfile = json.load(open('greetings.json', 'r'))
    hello = Message(**workfile['hello'])
    

    greetings.json中的数据:

    {
      "hello": {
        "greeting": "Hello there!"
      }
    }
    

    有什么可能出错的,对吧?

    **操作符是一个“传播”​​操作符,它像字典一样接受一个键/值对数据对象,并传播它——通常为函数提供关键字参数:

    def say(greeting, name):
        print(f'{greeting} to you, {name}!')
    
    
    d = {'greeting': 'hello', 'name': 'AnFa')
    say(**d)
    

    这也适用于您的情况,因为 JSON 对象作为字典加载,因此可以使用**运算符进行传播。由于 JSON 对象的属性与构造函数的关键字参数名称完全匹配,因此它可以工作。

    类似地,*运算符展开一个列表:

    xs = ['hello', 'AnFa']
    say(*xs)
    

    这具有相同的结果,但尝试将值作为位置参数传递。

    了解了以上内容,你可能也明白为什么有时会看到这个:

    def some_func(x, *args, **kwargs):
        print(x)
        some_other_func(*args, **kwargs)
    

    在这里,*args**kwargsargs(参数)和kwargs(关键字参数)中捕获位置和关键字参数,第二次,它们将它们传播回对some_other_func的调用。那些名字argskwargs并不神奇,它们只是约定俗成的。

    如果您想要一些风险较小的东西(由于上述原因),您可以为您的类提供 ‘to_json’ 和 ‘from_json’ 方法,但很快事情就会变得复杂,您可能想要查看现有的库,因为用户@LeiYang 建议(其中有很多)。

    2年前 0条评论