在Python中从JSON初始化嵌套类?

时间:2016-08-25 17:34:52

标签: python json api web-applications

编写API时,我经常需要从嵌套的JSON中初始化类,如

"Resources": {
    "MyCluster": {
        "Type": "AWS::EMR::Cluster",
        "Properties": {
            "Applications": [
                { "Name" : "Hadoop" },
                { "Name" : "SPARK" },
                { "Name" : "Ganglia" }
            ],
            "BootstrapActions" : [...],
            "Instances": {
                "AdditionalMasterSecurityGroups" : [{ "Fn::GetAtt" : ["rAllowJupyter","GroupId"] }],
                "Ec2KeyName" : { "Ref" : "EC2KeyName" },
                "Ec2SubnetId" : { "Ref" : "Subnet" },
                "MasterInstanceGroup": {
                    "InstanceCount": 1,
                    "InstanceType": { "Ref" : "InstanceType" }
                },
                "CoreInstanceGroup": {
                    "InstanceCount": { "Ref" : "CoreNodeCount" },
                    "InstanceType": { "Ref" : "InstanceType" }
                }
            },
            "Configurations": [...],
            "Name": "MyCluster",
            "JobFlowRole": "EMR_EC2_DefaultRole",
            "ServiceRole": "EMR_DefaultRole",
            "ReleaseLabel": "emr-4.6.0",
            "LogUri": "s3://path/to/logs/",
            "Tags": [
                { "Key": "Name", "Value": "aqa-spark"},
                { "Key": "Owner",   "Value": { "Ref" : "OwnerTag" }},
                { "Key": "Purpose", "Value": { "Ref" : "PurposeTag" }}
            ]
        }
    }
},

在我的代码中,这导致级联

# When my API receives such a ...
n_json = {"nested1": {"nested2" : { "nested3" : "..." }}}

# .. I need to instantiate a proper object out of it ...
nested1 = Nested1.from_json(json.loads(n_json))

# ... so I can later use the instance in OOP style.
nested1.nested2.run_an_intance_method()

对于每一层嵌套,这都会产生更多的重复性并且容易出错。有什么聪明的方法吗?

1 个答案:

答案 0 :(得分:1)

这是你如何从JSON创建一个嵌套对象(类似于PHP的方式)。要从JSON创建对象树(而不是解析JSON,这只是一个Python结构),请编写以下类:

class Nested:
    def __new__(cls, structure):
        self = super(Nested, cls).__new__(cls)
        if type(structure) is dict:
            self.__dict__ = {key: Nested(structure[key]) for key in structure}
        elif type(structure) is list:
            self = [Nested(item) for item in structure]
        else:
            self = structure
        return self

并从解析的JSON中调用它。例如:

import json

s = json.dumps({'a': 1, 'b': {'c': [1, 2, {'d': 3}], 'e': {'f': 'g'}}})

result = Nested(json.loads(s))

print(result.a)  #  1

print(result.b.c) # [1, 2, <__main__.Nested object at 0x00000297A983D828>]

print(result.b.c[0]) # 1

print(result.b.c[2].d) # 3

以下是该课程的工作原理:

    在其他任何事情之前调用
  1. __new__。这里我们构造一个对象的实例(空)

  2. 如果new是list,我们将self替换为嵌套对象列表,以便Nested({'a': [1, 2, 3]).a等于[Nested(1), Nested(2), Nested(3)](也等于[1, 2, 3],见数字4 )

  3. 如果new是dict,我们会为每个键创建一个具有相同名称的属性,并为其指定Nested(dict[key])

  4. 如果是其他任何类型,只需为self指定值(将self替换为值),以便Nested({'a': ['b', 'c', 'd']}).a[0]等于'b',而不是Nested(..)