gpt4 book ai didi

python - pickle 具有 __slots__ 的卡住数据类

转载 作者:太空狗 更新时间:2023-10-30 02:51:35 25 4
gpt4 key购买 nike

如何使用 __slots__ 对卡住数据类的实例进行 pickle?例如,以下代码在 Python 3.7.0 中引发异常:

import pickle
from dataclasses import dataclass

@dataclass(frozen=True)
class A:
__slots__ = ('a',)
a: int

b = pickle.dumps(A(5))
pickle.loads(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 3, in __setattr__
dataclasses.FrozenInstanceError: cannot assign to field 'a'

如果我删除 frozen__slots__,这会起作用。这只是一个错误吗?

最佳答案

问题来自 pickle 在设置插槽状态时使用实例的 __setattr__ 方法。

默认的__setstate__定义在_pickle.c line 6220load_build中.

对于state dict中的item,直接更新实例__dict__:

 if (PyObject_SetItem(dict, d_key, d_value) < 0)

而对于 slotstate 字典中的项目,使用实例的 __setattr__:

if (PyObject_SetAttr(inst, d_key, d_value) < 0)

现在因为实例被卡住,__setattr__ 在加载时引发 FrozenInstanceError

为了避免这种情况,您可以定义自己的 __setstate__ 方法,该方法将使用 object.__setattr__,而不是实例的 __setattr__

docs对此给出某种警告:

There is a tiny performance penalty when using frozen=True: __init__() cannot use simple assignment to initialize fields, and must use object.__setattr__().

定义 __getstate__ 也可能很好,因为实例 __dict__ 在您的情况下始终是 None。如果不这样做,__setstate__state 参数将是一个元组 (None, {'a': 5}),第一个value 是实例的 __dict__ 的值,第二个是 slotstate dict。

import pickle
from dataclasses import dataclass

@dataclass(frozen=True)
class A:
__slots__ = ('a',)
a: int

def __getstate__(self):
return dict(
(slot, getattr(self, slot))
for slot in self.__slots__
if hasattr(self, slot)
)

def __setstate__(self, state):
for slot, value in state.items():
object.__setattr__(self, slot, value) # <- use object.__setattr__


b = pickle.dumps(A(5))
pickle.loads(b)

我个人不会将其称为错误,因为 pickling 过程被设计为灵活的,但仍有改进功能的空间。 pickle 协议(protocol)的修订可以在未来解决这个问题。除非我遗漏了一些东西并且除了微小的性能损失之外,对所有插槽使用 PyObject_GenericSetattr 可能是一个合理的修复?

关于python - pickle 具有 __slots__ 的卡住数据类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55307017/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com