如何让类支持 pickle 序列化但排除某些敏感属性

8次阅读

要让类支持pickle序列化但排除敏感属性,需自定义__getstate__方法过滤password、api_key等字段,必要时用__setstate__重置其值。

如何让类支持 pickle 序列化但排除某些敏感属性

要让类支持 pickle 序列化但排除某些敏感属性,关键在于自定义序列化逻辑,避免将密码、密钥、临时连接对象等写入序列化数据。python 提供了 __getstate____setstate__ 两个特殊方法来精确控制哪些属性被保存和恢复。

使用 __getstate__ 过滤敏感字段

在序列化前,pickle 会检查实例是否有 __getstate__ 方法。如果有,就调用它获取要保存的字典;否则默认保存 __dict__。你可以在该方法中复制原始状态,并删掉不想持久化的键。

例如:

class User:     def __init__(self, name, password, api_key, temp_cache=None):         self.name = name         self.password = password      # 敏感         self.api_key = api_key      # 敏感         self.temp_cache = temp_cache  # 临时/非必要         self.created_at = time.time() 
def __getstate__(self):     # 获取当前状态字典     state = self.__dict__.copy()     # 排除敏感和临时字段     for attr in ['password', 'api_key', 'temp_cache']:         state.pop(attr, None)     return state

可选:用 __setstate__ 控制反序列化行为

如果被排除的属性在反序列化后需要默认值或重新初始化(比如重置为 None 或重建缓存),可以实现 __setstate__。它接收 __getstate__ 返回的字典,并用于更新实例状态。

例如:

def __setstate__(self, state):         # 恢复基本状态         self.__dict__.update(state)         # 显式初始化被排除的字段         self.password = None         self.api_key = None         self.temp_cache = {}

避免意外序列化描述符或动态属性

如果类中用了 @Property__slots__ 或描述符(如 dataclasses.field(repr=False)),注意:__getstate__ 默认只处理 __dict__。若用了 __slots__,需手动构造状态字典;若属性是通过描述符动态计算的,通常不应出现在 __dict__ 中,自然不会被序列化——但建议仍显式检查。

__slots__ 类,可这样写 __getstate__

def __getstate__(self):     state = {}     for slot in self.__slots__:         if hasattr(self, slot) and slot not in {'password', 'api_key'}:             state[slot] = getattr(self, slot)     return state

测试是否真正排除了敏感字段

别只看代码逻辑,实际验证一下:

  • pickle.dumps(obj) 得到字节
  • pickle.loads() 反序列化后检查 .password 是否为 None 或不存在
  • 也可用 pprint.pprint(pickletools.dis(pickle.dumps(obj))) 粗略查看序列化内容(不推荐用于生产判断,仅调试)

确保敏感字段既没出现在序列化结果里,也不会在反序列化后意外复活。

text=ZqhQzanResources