如何标记attrs类字段使其不参与deepcopy/pickle操作?
解决attrs类中排除字段在deepcopy和pickle中的方法
针对你给出的Foo类,要让_client字段不参与深拷贝(deepcopy)和序列化(pickle),可以通过以下两种简洁方式实现:
方法一:利用attrs字段参数+自定义特殊方法
处理pickle序列化
给_client字段添加getstate参数,让pickle时直接忽略该字段;同时自定义__setstate__方法,在反序列化时重新初始化_client:
import attrs import pickle from copy import deepcopy from some_app import Client @attrs.mutable class Foo: _credentials: str = attrs.field(validator=attrs.validators.instance_of(str)) _client: Client = attrs.field( init=False, validator=attrs.validators.instance_of(Client), default=attrs.Factory(lambda self: Client(self._credentials), takes_self=True), getstate=lambda self, value: None # pickle时不保存该字段 ) def bla(self): return self._client.do_stuff def __setstate__(self, state): # 反序列化时恢复状态并重新创建client self.__dict__.update(state) self._client = Client(self._credentials)
处理deepcopy深拷贝
在类中添加__deepcopy__方法,只复制核心的_credentials字段,新实例会自动通过默认工厂重新创建_client:
def __deepcopy__(self, memo): new_instance = Foo(_credentials=self._credentials) memo[id(self)] = new_instance return new_instance
方法二:统一重写__getstate__和__setstate__
这种方式可以同时覆盖pickle和deepcopy的行为,一次定义解决两个需求:
import attrs import pickle from copy import deepcopy from some_app import Client @attrs.mutable class Foo: _credentials: str = attrs.field(validator=attrs.validators.instance_of(str)) _client: Client = attrs.field( init=False, validator=attrs.validators.instance_of(Client), default=attrs.Factory(lambda self: Client(self._credentials), takes_self=True), ) def bla(self): return self._client.do_stuff def __getstate__(self): # 返回要序列化/拷贝的状态,主动排除_client state = self.__dict__.copy() del state['_client'] return state def __setstate__(self, state): # 恢复状态并重新初始化_client self.__dict__.update(state) self._client = Client(self._credentials)
验证效果
用以下代码可以测试功能是否正常:
# 创建原实例 foo = Foo(_credentials="test_token") print(foo._client) # 正常输出Client实例 # 测试pickle序列化/反序列化 pickled_data = pickle.dumps(foo) unpickled_foo = pickle.loads(pickled_data) print(unpickled_foo._client) # 输出新创建的Client实例,与原实例不同 # 测试deepcopy copied_foo = deepcopy(foo) print(copied_foo._client) # 输出新创建的Client实例,与原实例不同
内容的提问来源于stack exchange,提问作者maxwell_rob33
相关产品推荐
相关产品推荐

