Rob*_*ert 5 python json json-deserialization
我想将从 Web 服务获取的 JSON 解析为对象结构。因此,我正在json.JSONDecoder用一个object_hook方法实现 的子类。我还没有找到一个好方法来为给定的数据选择正确的类。对于具有相同属性的类,似乎不可能识别正确的属性,因为这需要知道密钥。让我们看一个例子:
我有以下课程:
class Post:
def __init__(self, title, user=None, group=None):
self.title = title
self.user = user
self.group = group
class Group:
def __init__(self, name):
self.name = name
class User:
def __init__(self, name):
self.name = name
Run Code Online (Sandbox Code Playgroud)
观察 和Group类User具有相同的属性。现在我的 JSONDecoder 看起来像这样:
class JSONDecoder(json.JSONDecoder):
def __init__(self, encoding="UTF-8"):
json.JSONDecoder.__init__(self, object_hook=self.dict_to_object)
def dict_to_object(self, d):
if "posts" in d:
return d["posts"]
if "title" in d:
if "user" in d:
return Post(d["title"], user=d["user"])
if "group" in d:
return Post(d["title"], group=d["group"])
if "name" in d:
# How to decide if User(d["name"]) or Group(d["name")?
return None
return None
Run Code Online (Sandbox Code Playgroud)
当它看到包含键“name”的字典时,它无法决定是否创建一个Group或一个User对象(因此我None现在返回)。
我想要解析的 JSON 字符串如下所示:
s = """
{ "posts" : [
{"title" : "Hello World", "user" : {"name" : "uli"}},
{"title" : "Hello Group", "group" : {"name" : "Workgroup"}}
]
}
"""
Run Code Online (Sandbox Code Playgroud)
这应该会产生一个 Post 对象列表,每个对象都有一个标题和一个组或用户。
如何以最好的方式解决这个问题?这种if-Statements的积累dict_to_object真的是正确的方法吗?(由于复杂的嵌套 JSON 结构,实际代码看起来更加混乱。)或者我应该使用其他模式或库吗?(尽管我更喜欢使用标准库。)
在这种情况下,IME 通常使用 JSON 解码,最好在解码时分配给通用字典,不要使用 object_hook,并推迟创建单独的类型化对象,直到所有解码后的第二次传递,此时您可以任意检查您正在处理的流和层次结构,即哪个对象是哪个对象的父/子/兄弟。(就像@BrenBam 说的)
使用 classmethod make_xyz 函数,而不是构造函数
object_hook通常看起来很诱人,但很少是您想要的东西。仅仅因为它的存在,它往往是错误的选择。只有当您始终能够 100% 确定每个对象使用哪个类时,这才是正确的选择(即使如此,只有在不传递状态的情况下很容易评估,即在对象挂钩中编写一个临时解析器时,这才是正确的选择) ),通常元素遵循一定的顺序,JSON 永远不会格式错误等。
在这里,您遇到了一个通用问题:在这种特定情况下,构造函数{"name" : "xyz"}无法知道它是什么类型的 JSON 对象,只有看到的父对象"user"/"group" :可以。一种解决方案是将所有类和构造函数重构为 classmethods make_group()、make_user()。但这只是将第二次解码传递到第一次解码传递中,没有特殊原因,给了我们一个巨大的脆弱的 object_hook 函数。IME 这很少是一个好主意。
| 归档时间: |
|
| 查看次数: |
830 次 |
| 最近记录: |