deepdiff——python自带的json对比库

工作中我们经常要两段代码的区别,或者需要查看接口返回的字段与预期是否一致,如何快速定位出两者的差异?除了一些对比的工具比如Beyond Compare、WinMerge等,或者命令工具diff(在linux环境下使用),其实Python中也提供了很多实现对比的库,比如deepdiff和difflib,这两个的区别是deepdiff显示的对比效果比较简洁,但是可以设置忽略的字段,difflib显示的对比结果可以是html的,比较详细。今天我们就学习一下快速实现代码和文件对比的库–deepdiff。


deepdiff是什么

deepdiff模块常用来校验两个对象是否一致,包含3个常用类,DeepDiff,DeepSearch和DeepHash,其中DeepDiff最常用,可以对字典,可迭代对象,字符串等进行对比,使用递归地查找所有差异。当然,也可以可以用来校验多种文件内容的差异,如txt、json、图片等…

deepdiff安装
pip install deepdiff

基本使用——类型或值不同

deepdiff类有个构造函数,大部分属性有默认值,通过修改这些值来进行过滤筛选等操作

from deepdiff import DeepDiff

exjson = {
    'code': 0,
    "message": "成功",
    "data": {
        "total": 28,
        "id": '123'
    }
}

jxjson = {
    'code': 1000000,
    "message": "成功",
    "data": {
        "total": 28,
        "id": 123
    }
}

res = DeepDiff(exjson, jxjson)
print(res)

打印结果(用json转换工具润色过):
# type_changes 代表类型不同
# values_changed 代表值不同
# root代表根节点
{
	"type_changes": {
		"root['data']['id']": {
			"old_type": "<class 'str'>",
			"new_type": "<class 'int'>",
			"old_value": "123",
			"new_value": 123
		}
	},
	"values_changed": {
		"root['code']": {
			"new_value": 1000000,
			"old_value": 0
		}
	}
}

基本使用——参数个数有余或有少
exjson = {'code': 0,"message": "成功","id": 100}
jxjson = {'code': 0,"message": "成功","id": 100,"pop": "BOOM!"}
res = DeepDiff(exjson, jxjson)
print(res)
打印结果:
{'dictionary_item_added': [root['pop']]} # 多出一个值pop

如果是将比对的两个字典前后顺序调转,也就是DeepDiff(jxjson, exjson)的话,会打印:
{'dictionary_item_removed': [root['pop']]} # 少了一个值pop

进阶使用——过滤大小写/无视顺序/忽略特定字段的比对

除了这三个用法,构造函数中还有其它属性可以修改使用,具体可以进入DeepDiff类查看。

from deepdiff import DeepDiff

# 列表是有序的,字典是无序的,比对时列表顺序不对会报错
# 但是通过设置ignore_order为True可以无视顺序进行比对
exjson = [1, 2, 3]
jxjson = [3, 2, 1]
res = DeepDiff(exjson, jxjson, ignore_order=True)
print(res)

# 将ignore_string_case设置为True可以过滤字符的大小写,无视字符之间大小写的区别
json1 = {"age": 18, "name": "hami"}
json2 = {"age": 18, "name": "Hami"}
res = DeepDiff(json1, json2, ignore_string_case=True)
print(res)

# 在exclude_paths中添加字段,在对比时会忽略该字符之间区别
# 这里age被忽略后,就会忽略该字段之间的检查
json1 = {"code": "200", "name": "hami", "usercode": "431123456789", "age": 18}
json2 = {"code": "200", "name": "hami", "usercode": "431123456789", "age": 20}
res = DeepDiff(json1, json2, exclude_paths={"age"})
print(res)

# 空字典代表比对无误
打印结果:
{}
{}
{}

比较少用——忽略数值类型的检查/忽略字符串
from decimal import Decimal
from deepdiff import DeepDiff

# 高精度的十进制计算,避免了浮点数运算中的精度丢失问题。
t1 = Decimal('10.01') # 数字类型
t2 = 10.01
# 忽略数值类型的检查
print(DeepDiff(t1, t2, ignore_numeric_type_changes=True))

# 忽略字符串(字符串前+b变为二进制)
res = DeepDiff(b'hello', 'hello', ignore_string_type_changes=True)
print(res)

结果:
{}
{}

deepdiff中deepSearch类的使用
from deepdiff import DeepSearch, DeepHash

# 查询对应字段的下标值(包含其中也算)
obj = ["long somewhere", "string", 0, "somewhere great!"]
item = 'some' # 大小写敏感的
ds = DeepSearch(obj, item, case_sensitive=True)
print(ds)

# DeepHash,将对应的val转化为Hash值
t1 = {"name": "yanan"}
res = DeepHash(t1)
print(res)

结果:
{'matched_values': ['root[0]', 'root[3]']}
{'name': '4bbeb3a6f8b1515275fb7ca2911273c1818f0284af9efe23c321126bb947d992', 'yanan': 'b7ae3162d12d47884599fc64d20c8490010fcb9d3896b6cb8337a5ed1a88c802', '!>*id2427106373440': '6a9957597125cb5fed2a4d10c98884efc9decb03735f8f396fb127158e35a68e'}