使用 JSON 在 Python 中创建 class 对象的最佳方法
Best way to use a JSON to create class objects in Python
我一直在练习使用 JSON 文件和 OOP,所以我想我会同时做这两者,但我一直在努力寻找最有效的方法来创建 class 个基于 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 class 对象的最佳方法吗?还是有更好的方法?
使用 **
运算符可能是首选方法,只要您的构造函数参数与 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!"
}
}
可能会出什么问题,对吗?
**
运算符是一个 'spreading' 运算符,它采用像字典一样的 key/value 对数据对象,并将其传播 - 通常为函数提供关键字参数:
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
和 **kwargs
用于捕获 args
(参数)和 kwargs
(关键字参数)中的位置参数和关键字参数,第二次,他们将它们传播回 some_other_func
的调用中。这些名称 args
和 kwargs
并不神奇,它们只是约定俗成。
如果你想要风险较小的东西(由于上面解释的原因),你可以提供 class 'to_json' 和 'from_json' 方法,但很快事情就会得到复杂,您可能想查看现有的库,正如用户@LeiYang 所建议的那样(其中有很多)。
我一直在练习使用 JSON 文件和 OOP,所以我想我会同时做这两者,但我一直在努力寻找最有效的方法来创建 class 个基于 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 class 对象的最佳方法吗?还是有更好的方法?
使用 **
运算符可能是首选方法,只要您的构造函数参数与 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!"
}
}
可能会出什么问题,对吗?
**
运算符是一个 'spreading' 运算符,它采用像字典一样的 key/value 对数据对象,并将其传播 - 通常为函数提供关键字参数:
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
和 **kwargs
用于捕获 args
(参数)和 kwargs
(关键字参数)中的位置参数和关键字参数,第二次,他们将它们传播回 some_other_func
的调用中。这些名称 args
和 kwargs
并不神奇,它们只是约定俗成。
如果你想要风险较小的东西(由于上面解释的原因),你可以提供 class 'to_json' 和 'from_json' 方法,但很快事情就会得到复杂,您可能想查看现有的库,正如用户@LeiYang 所建议的那样(其中有很多)。