Pickle一个冻结的数据类,该类具有__

2024-04-19 18:54:59 发布

您现在位置:Python中文网/ 问答频道 /正文

如何使用__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)
^{pr2}$

如果我删除frozen或{},这就可以了。这只是个虫子吗?在


Tags: 数据实例代码fromimporttruepickleclass
1条回答
网友
1楼 · 发布于 2024-04-19 18:54:59

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

默认的__setstate__是在^{} line 6220中的load_build中定义的。在

对于状态dict中的项,实例__dict__直接更新:

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

而对于slotstate dict中的项,则使用实例的__setattr__

^{pr2}$

现在,由于实例被冻结,__setattr__在加载时引发{}。在

为了避免这种情况,您可以定义自己的__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__在您的例子中始终是{},这可能也是一个好的选择。否则,__setstate__state参数将是一个元组(None, {'a': 5}),第一个值是实例的__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)

我个人不会说它是一个bug,因为酸洗过程的设计是灵活的,但是还有一些功能增强的空间。对酸洗规程的修订可以在将来解决这个问题。除非我遗漏了一些东西,并且除了性能损失之外,对所有插槽使用PyObject_GenericSetattr可能是一个合理的解决方案?在

相关问题 更多 >