欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Python JSON 操作 - JSON 与 Python 对象,自定义对象 之间的互相转化

程序员文章站 2024-02-03 11:17:04
...

前言

API 测试时,Request Body 和 Response Body 格式可能是JSON 格式,所以对 JSON 的处理显得非常重要。 关于 JSON 的概念请参考这篇《REST Assured 22 - JSON

Python 对 JSON 的操作非常方便,主要有下面 4 个方法。

方法 功能
json.dumps() 将 Python 对象编码成 JSON 字符串
json.loads() 将已编码的 JSON 字符串解码为 Python 对象
json.dump() 将Python内置类型序列化为json对象后写入文件
json.load() 读取文件中json形式的字符串元素转化为Python类型

内容提要:

  1. json.dumps() 实践
  2. json.loads() 实践
  3. json.dump() 实践
  4. json.loads() 实践
  5. 如何动态设置 JSON request body

Python 对象编码成 JSON 字符串 json.dumps()

1. 字典 dict 转化成 JSON

import json

d = {"key1" : "value1", "key2" : "value2"}
json_string = json.dumps(d)
print("dic: {}".format(d))
print("json string: {}".format(json_string))

输出:
dict 中 key/value都是单引号的,json 中的 key/value 是双引号的。

dic: {'key1': 'value1', 'key2': 'value2'}
json string: {"key1": "value1", "key2": "value2"}

2. 格式化输出 JSON
控制缩进,key value 之间的连接符

import json

d = {"key1" : "value1", "key2" : "value2"}
json_string_pretty_1 = json.dumps(d, indent=2, separators=(',', ':'))
json_string_pretty_2 = json.dumps(d, indent=4, separators=(',', '='))
print("json string pretty 1 :\n {}".format(json_string_pretty_1))
print("json string pretty 2 :\n {}".format(json_string_pretty_2))

输出:两种不同的格式

json string pretty 1 :
 {
  "key1":"value1",
  "key2":"value2"
}
json string pretty 2 :
 {
    "key1"="value1",
    "key2"="value2"
}

3. 按 Key 排序输出 JSON 字符串
sort_keys=True 按 key 排序

import json

d_dis_order = {"name" : "peter", "age": 18, "gender" : "men"}
json_in_order = json.dumps(d_no_order, indent=4, sort_keys=True)

print("dic disorder:\n {}".format(d_dis_order))
print("json string inorder:\n {}".format(json_in_order))

输出:

dic disorder:
 {'name': 'peter', 'age': 18, 'gender': 'man'}
json string inorder:
 {
    "age": 18,
    "gender": "man",
    "name": "peter"
}

4. 将类对象转化成 JSON 字符串
自定义对象转化成 JSON 字符串,需要自定义一个 JSONEncoder 子类来覆盖默认的 系列化赋值给 cls 参数。

To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.

import json
from json import JSONEncoder

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

class PersonEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__        
        
peter = Person("Peter", 18, "Men")
json_peter = json.dumps(peter, indent=4, cls=PersonEncoder)
print("peter object:\n{}".format(peter))
print("json peter:\n{}".format(json_peter))

输出:

peter object:
<__main__.Person object at 0x000001FE156C9648>
json peter:
{
    "name": "Peter",
    "age": 18,
    "gender": "Men"
}

JSON 字符串解码为 Python 对象 json.loads()

1. 访问 JSON 中的值
通过 json.loads() 方法将 JSON 字符串转化成 python 的 dict 对象就可以访问其键值了

import json

json_string = '''{"name":"peter", "age":18, "gender":"Men"}'''
data = json.loads(json_string)

print("json string:\n{}".format(json_string))
print("data:\n{}".format(data))
print("age: {}".format(data["age"]))

输出:

json string:
{"name":"peter", "age":18, "gender":"Men"}
data:
{'name': 'peter', 'age': 18, 'gender': 'Men'}
age: 18

2. 访问 JSON 嵌套对象

获取 JSON 字符串中 salary 的值

import json

json_string = '''
                {
                    "company": {
                        "person": {
                            "name": "peter",
                            "age": 18,
                            "gender": "Men",
                            "pay": {
                                "salary": 3000,
                                "bonus": 5000
                            }
                        }
                    }
                }
                '''                
data = json.loads(json_string)
print("json string:\n{}".format(json_string))
print("data:\n{}".format(data))
print("salary: {}".format(data["company"]["person"]["pay"]["salary"]))

输出:
通过 data[“company”][“person”][“pay”][“salary”] 访问到嵌套的值

json string:

                {
                    "company": {
                        "person": {
                            "name": "peter",
                            "age": 18,
                            "gender": "Men",
                            "pay": {
                                "salary": 3000,
                                "bonus": 5000
                            }
                        }
                    }
                }

data:
{'company': {'person': {'name': 'peter', 'age': 18, 'gender': 'Men', 'pay': {'salary': 3000, 'bonus': 5000}}}}
salary: 3000

3. 将 JSON 字符串转化成类对象
object_hook 用于将 JSON 字符串解码成自定义的类对象, 默认object_hook= None 是解码成 dict. 所以要自定义一个解码方法。

object_hook is an optional function that will be called with the result of any object literal decode (a dict). The return value of object_hook will be used instead of the dict. This feature can be used to implement custom decoders (e.g. JSON-RPC class hinting).

import json

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

def PersonDecoder(obj):
        return Person(obj['name'], obj['age'], obj['gender'])   

person_json_string = '''{"name" : "peter", "age": 18, "gender" : "men"}'''    

person_object = json.loads(person_json_string, object_hook=PersonDecoder)
print("person json string:\n{}".format(person_json_string))
print("peson object:\n{}".format(person_object))
print("name:{}\nage:{}\ngender:{}".format(person_object.name, person_object.age, person_object.gender))

输出:

person json string:
{"name" : "peter", "age": 18, "gender" : "men"}
peson object:
<__main__.Person object at 0x000001FFBCF4AA88>
name:peter
age:18
gender:men

4. 判断 JSON 格式是否正确

下面这个 JSON String 少了一个 ’ } '

json_string = '''
                {
                    "company": {
                        "person": {
                            "name": "peter",
                            "age": 18,
                            "gender": "Men",
                            "pay": {
                                "salary": 3000,
                                "bonus": 5000
                            }
                        }
                    
                }
                '''                

def is_valid_JSON(json_data):
    try:
        json.loads(json_data)
    except ValueError as err:
        return False
    return True

is_valid = is_valid_JSON(json_string)
print("json string is valid: {}".format(is_valid))

输出:

json string is valid: False

5. 获取 JSON 字符串中某个 key 所有的值

获取下面 JSON 字符串中所有 name 的 value

import json

json_string = '''
            [
            {
                "id":1,
                "name":"peter",
                "hobby":[
                    "reading",
                    "movie"
                ]
            },
            {
                "id":2,
                "name":"lina",
                "hobby":[
                    "sleep",
                    "shopping"
                ]
            }
            ]
            '''
json_data = json.loads(json_string)

name_list = [item.get("name") for item in json_data]
print(name_list)

输出:

['peter', 'lina']

将Python内置类型序列化为json对象后写入文件 json.dump()

1. 字典 dict 转化成 JSON 写入文件

import json

d = {"name" : "peter", "age": 18, "gender" : "men"} 
           
with open("json.txt", 'w+') as f:
    json.dump(d, f, indent=4)

json.txt 内容
Python JSON 操作 - JSON 与 Python 对象,自定义对象 之间的互相转化
2. 自定义类对象转化成 JSON 写入文本
需要自定义一个 JSONEncoder 子类来覆盖默认的 系列化赋值给 cls 参数。

import json
from json import JSONEncoder

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender
        
class PersonEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__ 

person = Person("peter", 18, "men")            
with open("json.txt", 'w+') as f:
    json.dump(d, f, indent=4, cls=PersonEncoder)

json.txt 内容
Python JSON 操作 - JSON 与 Python 对象,自定义对象 之间的互相转化

读取文件中 json 形式的字符串元素转化为Python类型 json.load()

1. 文本中 json 字符串转化成 dict

with open("json.txt", 'r') as f:
    data = json.load(f)
print(data)

输出:

{'name': 'peter', 'age': 18, 'gender': 'men'}

2. 文本中的 json 字符串转化成自定义的类对象
object_hook 用于将 JSON 字符串解码成自定义的类对象, 默认object_hook= None 是解码成 dict. 所以要自定义一个解码方法。

import json

class Person:
    def __init__(self, name, age, gender):
        self.name = name
        self.age = age
        self.gender = gender

def PersonDecoder(obj):
        return Person(obj['name'], obj['age'], obj['gender']) 

with open("json.txt", 'r') as f:
    person = json.load(f, object_hook=PersonDecoder)
print("name:{}\nage:{}\ngender:{}".format(person.name, person.age, person.gender))

如何动态设置 JSON request body

有时我们把 json 的 request 放在一个文本文件中,但并不是每次请求都用固定的 json body,需要动态地修改其中的值,最后还得转化成 json 字符串做为request body。

例如:json.txt 文本的内容
需要修改 collection-id 字段的值,将改动后的 json 字符串传入 request 作为 body

注意:json body key 都是双引号的,所以一定要将 python 的对象转化成 json 字符串,才能传入 request。

{
	"search": {
		"query": {
					"collection-id": ["collection"]
				
		}
	},
	"targets": [
		{
			"type": "subscription-id",
			"value": [
				1234
			]
		}
	]
}
import json

with open("json.txt", 'r') as f:
    data = json.load(f)
    
print("data:\n{}".format(data))

data["search"]["query"]["collection-id"] = ["collection_1", "collection_2", "collection_3"]
print("new data:\n{}".format(data))

json_data = json.dumps(data, indent=4)
print("json data:\n{}".format(json_data))

输出:

data:
{'search': {'query': {'collection-id': ['collection']}}, 'targets': [{'type': 'subscription-id', 'value': [1234]}]}
new data:
{'search': {'query': {'collection-id': ['collection_1', 'collection_2', 'collection_3']}}, 'targets': [{'type': 'subscription-id', 'value': [1234]}]}
json data:
{
    "search": {
        "query": {
            "collection-id": [
                "collection_1",
                "collection_2",
                "collection_3"
            ]
        }
    },
    "targets": [
        {
            "type": "subscription-id",
            "value": [
                1234
            ]
        }
    ]
}