__getstate__ 与 __setstate__ 两个魔法方法分别用于Python 对象的序列化与反序列化


在序列化时, _getstate__ 可以指定将那些信息记录下来, 而 __setstate__ 指明如何利用已记录的信息


先创建一个基类

class Demo:
    def __init__(self, name, age=0):
        self.name = name
        self.age = age

    def __str__(self):
        return f"name: {self.name}\nage: {self.age}"

继承Demo, 并实现 __getstate__ 与 __setstate__ 方法

class DemoState1(Demo):
    # 反序列化时调用, state 是 __getstate__ 的返回对象
    def __setstate__(self, state):
        print("invoke __setstate__")
        # 将记录的信息("Python3") 赋给 name
        self.name = state
        self.age = 31

    # 序列化时调用
    def __getstate__(self):
        print("invoke __getstate__")
        # 记录信息 “Python3”
        return "Python3"

测试调用流程

In [3]: import pickle

In [4]: demo_1 = DemoState1("None") # "None" 0

In [5]: print(demo_1)
name: None
age: 0

In [6]: demo_bytes_1 = pickle.dumps(demo_1) # 序列化为字节串
invoke __getstate__

In [7]: print(demo_bytes_1) # 仅对象中的字符串信息是可读的
b'\x80\x03c__main__\nDemoState1\nq\x00)\x81q\x01X\x07\x00\x00\x00Python3q\x02b.'

In [8]: demo_object_1 = pickle.loads(demo_bytes_1)
invoke __setstate__

In [9]: print(demo_object_1)
name: Python3
age: 31

可以省略 __setstate__, 但 __getstate__ 必须返回一个字典, 字典的内容被加载到当前的对象

class DemoState2(Demo):
    # 省略 __setstate__
    # 自动将 __getstate__ 的返回对象添加到当前对象的属性

    # 序列化时调用
    def __getstate__(self):
        # 必须返回字典
        state = {"name": "C", "age": 50, "address": "Bell Lab"}
        return state

测试

In [11]: demo_2 = DemoState2("None")

In [12]: demo_bytes_2 = pickle.dumps(demo_2)

In [13]: print(pickle.loads(demo_bytes_2))
name: C
age: 50

对象本身没有 address 属性, 因此反序列化时被忽略了


如果 __getstate__ 与 __setstate__ 都省略, 那么就是默认情况, 自动保存和加载对象的属性字典 __dict__

In [14]: js = Demo("JavaScript", 26)

In [15]: js.__dict__ # 对象的属性字典                                     
Out[16]: {'name': 'JavaScript', 'age': 26}

In [17]: js_bytes = pickle.dumps(js)

In [18]: print(pickle.loads(js_bytes))
name: JavaScript
age: 26

大多数时候保持默认情况即可, 但是遇到不可序列化的对象, 例如 self.file = open("filename"), 就需要忽略掉该属性

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐