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

前言

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 内容
在这里插入图片描述
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 内容
在这里插入图片描述

读取文件中 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
            ]
        }
    ]
}

猜你喜欢

转载自blog.csdn.net/wumingxiaoyao/article/details/121437016
今日推荐