IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Python学习:python对象转换json字符串 -> 正文阅读

[Python知识库]Python学习:python对象转换json字符串

1.问题

json是网络传输比较简单易用。python中,jsondict对象可以相互转换,首先我们看下简单的dict对象转换。

student = {
    'name': 'chaos',
    'age': 18,
    'school': {
        'name': "tsinghua"
    }
}

print(json.dumps(student))

输出为:

{"name": "chaos", "age": 18, "school": {"name": "tsinghua"}}

一般情况下,我们遇到的类型一般并不是dict,而是class。我们的问题是pythonclass如何转换成json呢?虽然pythonclassdict比较像,转化成dict是比较麻烦的过程。本文我们就看看如何把python对象转换为dict

2.方案

首先我们直接使用@dataclass进行类型的定义,然后再看普通的class类型。我们先定义类型:

@dataclass
class School:
    name: str

@dataclass
class Student:
    name: str
    age: int
    school: School

class有个属性__dict__,该属性包换了class的属性成员。最初的版本转换版本代码如下:

def obj2json(obj, atom_type: list = None, collect_type: list = None) -> str:
    def _obj2dict(in_obj, dc: dict, _atom_type, _collect_type):
        for key, value in in_obj.__dict__.items():
            if value is None:
                dc[key] = None
            elif isinstance(value, _atom_type):
                dc[key] = value
            elif isinstance(value, _collect_type):
                dc[key] = list()
                for item in value:
                    sub_dc = dict()
                    _obj2dict(item, sub_dc, _atom_type, _collect_type)
                    dc[key].append(sub_dc)
            else:
                dc[key] = dict()
                _obj2dict(value, dc[key], _atom_type, _collect_type)

    ret = dict()
    
    # 直接转化json节点的类型
    if not atom_type:
        _atom_type = (int, float, str, bool, bytes)
    else:
        _atom_type = tuple(set(atom_type + [int, float, str, bool, bytes]))
   
    # 数组类型 
    if not collect_type:
        _collect_type = (set, tuple, list)
    else:
        _collect_type = tuple(set(collect_type + [set, tuple, list]))
    _obj2dict(obj, ret, _atom_type, _collect_type)

    return json.dumps(ret)
  • _atom_type类型参数,表示直接转换为json节点。比如intstr。默认情况下,并没有包换复数类型Complex
  • _collect_type类型参数,表示转换为json的数组节点,比如listtuple等等。

测试代码如下:

student = Student(name='chaos', age=18, school=School('tsinghua'))
ret = obj2json0(student)
print(ret)

输出:

{"name": "chaos", "age": 18, "school": {"name": "tsinghua"}}

这一版本其实看上去不错。不过,遇到下面这个情况时,转换就出了问题。

@dataclass
class School:
    name: str

@dataclass
class Student:
    name: str
    age: int
    school: School
    contact: dict

def test_dataclass_002():
    ret = json.dumps(student)
    assert ret == {"name": "chaos", "age": 18, "school": {"name": "tsinghua"}}

def test_dataclass_003():
    student = Student(name='chaos', age=18, school=School('tsinghua'), contact=dict(number='13988889999'))
    ret = obj2json0(student)
    print(ret)

运行时会抛出异常:

in_obj = {'number': '13988889999'}, dc = {}
_atom_type = (<class 'int'>, <class 'float'>, <class 'str'>, <class 'bool'>, <class 'bytes'>)
_collect_type = (<class 'set'>, <class 'tuple'>, <class 'list'>)

    def _obj2dict(in_obj, dc: dict, _atom_type, _collect_type):
>       for key, value in in_obj.__dict__.items():
E       AttributeError: 'dict' object has no attribute '__dict__'

问题是对于内置类型dict的对象,没有__dict__属性。这也很好解决,先判定一下是否dict类型,代码如下:

def obj2json(obj, atom_type: list = None, collect_type: list = None) -> str:
    def _obj2dict(in_obj, dc: dict, _atom_type, _collect_type):
        if isinstance(in_obj, dict):
            dict_obj = in_obj
        else:
            dict_obj = in_obj.__dict__
        for key, value in dict_obj.items():
            if value is None:
                dc[key] = None
            elif isinstance(value, _atom_type):
                dc[key] = value
            elif isinstance(value, dict):
                dc[key] = dict()
                _obj2dict(value, dc[key], _atom_type, _collect_type)
            elif isinstance(value, _collect_type):
                dc[key] = list()
                for item in value:
                    sub_dc = dict()
                    _obj2dict(item, sub_dc, _atom_type, _collect_type)
                    dc[key].append(sub_dc)
            else:
                dc[key] = dict()
                _obj2dict(value, dc[key], _atom_type, _collect_type)

    ret = dict()
    if not atom_type:
        _atom_type = (int, float, str, bool, bytes)
    else:
        _atom_type = tuple(set(atom_type + [int, float, str, bool, bytes]))
    if not collect_type:
        _collect_type = (set, tuple, list)
    else:
        _collect_type = tuple(set(collect_type + [set, tuple, list]))
    _obj2dict(obj, ret, _atom_type, _collect_type)
    return json.dumps(ret)

我们现在看看上述的转换,能否适用于普通的class。代码如下:

class School:
    def __init__(self, name):
        self.name = name

class Student:
    def __init__(self, name, age, contact, school):
        self.name = name
        self.age = age
        self.school = school
        self.contact = contact

    def get_name(self):
        return self.name

    @classmethod
    def get_class_name(cls):
        return "Student"

student = Student(name='chaos', age=18, contact=dict(number='13999998888'), school=School('tsinghua'))
ret = obj2json(student)
print(ret)

输出如下:

{"name": "chaos", "age": 18, "school": {"name": "tsinghua"}, "contact": {"number": "13999998888"}}

看上去很好,新定义的对象函数或者类函数,都没有影响到结果输出。

3.讨论

到目前为止,转换函数看上去不错。不过,并不完美,此问题比看上去复杂。比如,对于双向链表这样的函数,就没有办法处理,会出现循环引用。比如下面这个代码:

class TreeNode:
    def __init__(self, value, pre_node=None, next_node=None):
        self.value = value
        self.pre_node = pre_node
        self.next_node = next_node

 root = TreeNode(10)
    next_root = TreeNode(11)
    root.pre_node = next_root
    root.next_node = next_root
    next_root.pre_node = root
    next_root.next_node = root
    obj2json(root)

进一步思考的话,可能也会有解决办法,但是我们需要的是解决当前的问题,不一定需要解决所有情况下的问题。如果实现过于复杂的话,不妨到此为止,只要能解决当前的问题就行,将来遇到再说也不迟。

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-10-04 12:48:17  更:2021-10-04 12:50:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 18:42:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码