在Python中,如果你想防止某些字段被pickle序列化,可以使用__reduce__()
方法来自定义pickle行为。__reduce__()
方法允许你返回一个元组,其中包含要在对象被pickle时调用的函数以及传递给该函数的参数。下面就是我遇到的问题以及最终解决方案。
1、问题背景
在使用 Python 的 Pickle 模块对对象进行序列化时,我们有时希望排除某些字段,以防止其被序列化。这可能是由于这些字段包含敏感信息,或者只是因为它们是临时变量,不应被持久化。
2、解决方案
有几种方法可以防止某些字段被 Pickle 序列化。
- 使用
__getstate__
和__setstate__
方法
__getstate__
和 __setstate__
是 Python 内置的特殊方法,可以让我们自定义对象的序列化和反序列化行为。我们可以通过重写这些方法来控制哪些字段被序列化。
class Something(object):
def __init__(self):
self._thing_id = 0
self._cached_thing = None
def __getstate__(self):
# 只序列化 `_thing_id` 字段
return {'_thing_id': self._thing_id}
def __setstate__(self, state):
# 从 `state` 中恢复 `_thing_id` 字段
self._thing_id = state['_thing_id']
- 使用
__getnewargs__
和__getnewargs_ex__
方法
__getnewargs__
和 __getnewargs_ex__
是 Python 内置的特殊方法,可以让我们在序列化对象时传递自定义参数。我们可以通过重写这些方法来控制哪些字段被序列化。
class Something(object):
def __init__(self, thing_id):
self._thing_id = thing_id
self._cached_thing = None
def __getnewargs__(self):
# 只传递 `_thing_id` 参数
return (self._thing_id,)
def __getnewargs_ex__(self):
# 只传递 `_thing_id` 参数
return (self._thing_id,), {}
- 使用
__reduce__
方法
__reduce__
是 Python 内置的特殊方法,可以让我们自定义对象的序列化行为。我们可以通过重写这个方法来控制哪些字段被序列化。
class Something(object):
def __init__(self, thing_id):
self._thing_id = thing_id
self._cached_thing = None
def __reduce__(self):
# 只返回 `_thing_id` 参数
return (self.__class__, (self._thing_id,), {})
- 使用
_blacklist
变量
我们可以使用 _blacklist
变量来指定哪些字段不应被序列化。在 __getstate__
方法中,我们可以使用这个变量来过滤掉不需要序列化的字段。
class Something(object):
def __init__(self, thing_id):
self._thing_id = thing_id
self._cached_thing = None
# 黑名单
_blacklist = ['_cached_thing']
def __getstate__(self):
# 只序列化除 `_blacklist` 中的字段以外的所有字段
return {k: v for k, v in self.__dict__.items() if k not in self._blacklist}
- 使用命名约定
为了避免在每个类中都指定 _blacklist
变量,我们可以使用命名约定来标记哪些字段不应被序列化。例如,我们可以将不应被序列化的字段命名为 _cached_xxx
。这样,我们在 __getstate__
方法中就可以直接过滤掉所有以 _cached_xxx
开头的字段。
class Something(object):
def __init__(self, thing_id):
self._thing_id = thing_id
self._cached_thing = None
def __getstate__(self):
# 只序列化除了以下列 "_cached_" 开头的字段之外的所有字段
return {k: v for k, v in self.__dict__.items() if not k.startswith('_cached_')}
在这个示例中,MyClass
类有两个字段:sensitive_data
和non_sensitive_data
。我们通过定义__reduce__()
方法来指定pickle时应该调用的函数。在这个函数中,我们只传递了non_sensitive_data
字段,而忽略了self.sensitive_data
字段,从而防止了敏感数据被pickle序列化。
我们可以根据实际需求自定义__reduce__()
方法来选择哪些字段需要被pickle序列化,哪些字段不需要。
如果有任何问题可以留言讨论交流。