Pickle a frozen dataclass that has __slots__Usage of __slots__?GAE: ValueError: insecure string picklenamespace on python picklePickle errors with Python 3why Can't pickle a defauldict of objects in python?load pickle file for counvectorizerEOFError in pickle.load and file not found errorPickle: Storing the contents of variableHow can I save an Object like an Image Classifier prepared using Keras to my any file using Python?Problems in importing split in Python
If 1. e4 c6 is considered as a sound defense for black, why is 1. c3 so rare?
Feels like I am getting dragged into office politics
How long can a 35mm film be used/stored before it starts to lose its quality after expiry?
Floor tile layout process?
Why is Thanos so tough at the beginning of "Avengers: Endgame"?
Airbnb - host wants to reduce rooms, can we get refund?
Is this homebrew race based on Draco Volans balanced?
Who died in the Game of Thrones episode, "The Long Night"?
How to reply this mail from potential PhD professor?
Printing a string when grep does not get a match
What happened to Rhaegal?
Does it look bad as a candidate if I apply to two post-doctoral positions at the same national research laboratory?
Declining welcome lunch invitation at new job due to Ramadan
How do you center multiple equations that have multiple steps?
Unexpected email from Yorkshire Bank
Write to EXCEL from SQL DB using VBA script
When and why did journal article titles become descriptive, rather than creatively allusive?
Can commander tax be proliferated?
Password expiration with Password manager
How did Captain America use this power?
Copy line and insert it in a new position with sed or awk
Binary Numbers Magic Trick
How did Arya manage to disguise herself?
Can I use 1000v rectifier diodes instead of 600v rectifier diodes?
Pickle a frozen dataclass that has __slots__
Usage of __slots__?GAE: ValueError: insecure string picklenamespace on python picklePickle errors with Python 3why Can't pickle a defauldict of objects in python?load pickle file for counvectorizerEOFError in pickle.load and file not found errorPickle: Storing the contents of variableHow can I save an Object like an Image Classifier prepared using Keras to my any file using Python?Problems in importing split in Python
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
How do I pickle an instance of a frozen dataclass with __slots__? For example, the following code raises an exception in 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'
This works if I remove either the frozen or the __slots__. Is this just a bug?
python pickle slots python-dataclasses
add a comment |
How do I pickle an instance of a frozen dataclass with __slots__? For example, the following code raises an exception in 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'
This works if I remove either the frozen or the __slots__. Is this just a bug?
python pickle slots python-dataclasses
add a comment |
How do I pickle an instance of a frozen dataclass with __slots__? For example, the following code raises an exception in 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'
This works if I remove either the frozen or the __slots__. Is this just a bug?
python pickle slots python-dataclasses
How do I pickle an instance of a frozen dataclass with __slots__? For example, the following code raises an exception in 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'
This works if I remove either the frozen or the __slots__. Is this just a bug?
python pickle slots python-dataclasses
python pickle slots python-dataclasses
asked Mar 22 at 19:59
drhagendrhagen
3,21942646
3,21942646
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The problem comes from pickle using the __setattr__ method of the instance when setting the state of the slots.
The default __setsate__ is defined in load_build in _pickle.c line 6220.
For the items in the state dict, the instance __dict__ is updated directly:
if (PyObject_SetItem(dict, d_key, d_value) < 0)
whereas for the items in the slotstate dict, the instance's __setattr__ is used:
if (PyObject_SetAttr(inst, d_key, d_value) < 0)
Now because the instance is frozen, __setattr__ raises FrozenInstanceError when loading.
To circumvent this, you can define your own __setstate__ method which will use object.__setattr__, and not the instance's __setattr__.
The docs give some sort of warning for this:
There is a tiny performance penalty when using frozen=True:
__init__()cannot use simple assignment to initialize fields, and must useobject.__setattr__().
It may also be good to define __getstate__ as the instance __dict__ is always None in your case. If you don't, the state argument of __setstate__ will be a tuple (None, 'a': 5), the first value being the value of the instance's __dict__ and the second the 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)
I personally would not call it a bug as the pickling process is designed to be flexible, but there is room for a feature enhancement. A revision of the pickling protocol could fix this in future. Unless I am missing something and aside of the tiny performance penalty, using PyObject_GenericSetattr for all the slots might be a reasonable fix?
I updated the previously deleted answer. It all boils down to creating your own__setstate__method to avoid a call to the instance's__setattr__.
– Jacques Gaudin
Mar 23 at 15:27
1
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
@Arne Good point, I just had a look in the source code ofpickleand it seems that the other attributes are dealt with by modifying__dict__directly whereas the slots use__setattr__. I'll take a deeper look and update.
– Jacques Gaudin
Mar 23 at 22:50
2
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
@drhagen Great, I'll try to compile withPyObject_GenericSetattrwhen I'll get a chance. Fingers crossed!
– Jacques Gaudin
Mar 25 at 16:40
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55307017%2fpickle-a-frozen-dataclass-that-has-slots%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The problem comes from pickle using the __setattr__ method of the instance when setting the state of the slots.
The default __setsate__ is defined in load_build in _pickle.c line 6220.
For the items in the state dict, the instance __dict__ is updated directly:
if (PyObject_SetItem(dict, d_key, d_value) < 0)
whereas for the items in the slotstate dict, the instance's __setattr__ is used:
if (PyObject_SetAttr(inst, d_key, d_value) < 0)
Now because the instance is frozen, __setattr__ raises FrozenInstanceError when loading.
To circumvent this, you can define your own __setstate__ method which will use object.__setattr__, and not the instance's __setattr__.
The docs give some sort of warning for this:
There is a tiny performance penalty when using frozen=True:
__init__()cannot use simple assignment to initialize fields, and must useobject.__setattr__().
It may also be good to define __getstate__ as the instance __dict__ is always None in your case. If you don't, the state argument of __setstate__ will be a tuple (None, 'a': 5), the first value being the value of the instance's __dict__ and the second the 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)
I personally would not call it a bug as the pickling process is designed to be flexible, but there is room for a feature enhancement. A revision of the pickling protocol could fix this in future. Unless I am missing something and aside of the tiny performance penalty, using PyObject_GenericSetattr for all the slots might be a reasonable fix?
I updated the previously deleted answer. It all boils down to creating your own__setstate__method to avoid a call to the instance's__setattr__.
– Jacques Gaudin
Mar 23 at 15:27
1
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
@Arne Good point, I just had a look in the source code ofpickleand it seems that the other attributes are dealt with by modifying__dict__directly whereas the slots use__setattr__. I'll take a deeper look and update.
– Jacques Gaudin
Mar 23 at 22:50
2
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
@drhagen Great, I'll try to compile withPyObject_GenericSetattrwhen I'll get a chance. Fingers crossed!
– Jacques Gaudin
Mar 25 at 16:40
add a comment |
The problem comes from pickle using the __setattr__ method of the instance when setting the state of the slots.
The default __setsate__ is defined in load_build in _pickle.c line 6220.
For the items in the state dict, the instance __dict__ is updated directly:
if (PyObject_SetItem(dict, d_key, d_value) < 0)
whereas for the items in the slotstate dict, the instance's __setattr__ is used:
if (PyObject_SetAttr(inst, d_key, d_value) < 0)
Now because the instance is frozen, __setattr__ raises FrozenInstanceError when loading.
To circumvent this, you can define your own __setstate__ method which will use object.__setattr__, and not the instance's __setattr__.
The docs give some sort of warning for this:
There is a tiny performance penalty when using frozen=True:
__init__()cannot use simple assignment to initialize fields, and must useobject.__setattr__().
It may also be good to define __getstate__ as the instance __dict__ is always None in your case. If you don't, the state argument of __setstate__ will be a tuple (None, 'a': 5), the first value being the value of the instance's __dict__ and the second the 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)
I personally would not call it a bug as the pickling process is designed to be flexible, but there is room for a feature enhancement. A revision of the pickling protocol could fix this in future. Unless I am missing something and aside of the tiny performance penalty, using PyObject_GenericSetattr for all the slots might be a reasonable fix?
I updated the previously deleted answer. It all boils down to creating your own__setstate__method to avoid a call to the instance's__setattr__.
– Jacques Gaudin
Mar 23 at 15:27
1
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
@Arne Good point, I just had a look in the source code ofpickleand it seems that the other attributes are dealt with by modifying__dict__directly whereas the slots use__setattr__. I'll take a deeper look and update.
– Jacques Gaudin
Mar 23 at 22:50
2
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
@drhagen Great, I'll try to compile withPyObject_GenericSetattrwhen I'll get a chance. Fingers crossed!
– Jacques Gaudin
Mar 25 at 16:40
add a comment |
The problem comes from pickle using the __setattr__ method of the instance when setting the state of the slots.
The default __setsate__ is defined in load_build in _pickle.c line 6220.
For the items in the state dict, the instance __dict__ is updated directly:
if (PyObject_SetItem(dict, d_key, d_value) < 0)
whereas for the items in the slotstate dict, the instance's __setattr__ is used:
if (PyObject_SetAttr(inst, d_key, d_value) < 0)
Now because the instance is frozen, __setattr__ raises FrozenInstanceError when loading.
To circumvent this, you can define your own __setstate__ method which will use object.__setattr__, and not the instance's __setattr__.
The docs give some sort of warning for this:
There is a tiny performance penalty when using frozen=True:
__init__()cannot use simple assignment to initialize fields, and must useobject.__setattr__().
It may also be good to define __getstate__ as the instance __dict__ is always None in your case. If you don't, the state argument of __setstate__ will be a tuple (None, 'a': 5), the first value being the value of the instance's __dict__ and the second the 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)
I personally would not call it a bug as the pickling process is designed to be flexible, but there is room for a feature enhancement. A revision of the pickling protocol could fix this in future. Unless I am missing something and aside of the tiny performance penalty, using PyObject_GenericSetattr for all the slots might be a reasonable fix?
The problem comes from pickle using the __setattr__ method of the instance when setting the state of the slots.
The default __setsate__ is defined in load_build in _pickle.c line 6220.
For the items in the state dict, the instance __dict__ is updated directly:
if (PyObject_SetItem(dict, d_key, d_value) < 0)
whereas for the items in the slotstate dict, the instance's __setattr__ is used:
if (PyObject_SetAttr(inst, d_key, d_value) < 0)
Now because the instance is frozen, __setattr__ raises FrozenInstanceError when loading.
To circumvent this, you can define your own __setstate__ method which will use object.__setattr__, and not the instance's __setattr__.
The docs give some sort of warning for this:
There is a tiny performance penalty when using frozen=True:
__init__()cannot use simple assignment to initialize fields, and must useobject.__setattr__().
It may also be good to define __getstate__ as the instance __dict__ is always None in your case. If you don't, the state argument of __setstate__ will be a tuple (None, 'a': 5), the first value being the value of the instance's __dict__ and the second the 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)
I personally would not call it a bug as the pickling process is designed to be flexible, but there is room for a feature enhancement. A revision of the pickling protocol could fix this in future. Unless I am missing something and aside of the tiny performance penalty, using PyObject_GenericSetattr for all the slots might be a reasonable fix?
edited Mar 26 at 7:34
Arne
3,01822444
3,01822444
answered Mar 22 at 20:09
Jacques GaudinJacques Gaudin
6,92232246
6,92232246
I updated the previously deleted answer. It all boils down to creating your own__setstate__method to avoid a call to the instance's__setattr__.
– Jacques Gaudin
Mar 23 at 15:27
1
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
@Arne Good point, I just had a look in the source code ofpickleand it seems that the other attributes are dealt with by modifying__dict__directly whereas the slots use__setattr__. I'll take a deeper look and update.
– Jacques Gaudin
Mar 23 at 22:50
2
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
@drhagen Great, I'll try to compile withPyObject_GenericSetattrwhen I'll get a chance. Fingers crossed!
– Jacques Gaudin
Mar 25 at 16:40
add a comment |
I updated the previously deleted answer. It all boils down to creating your own__setstate__method to avoid a call to the instance's__setattr__.
– Jacques Gaudin
Mar 23 at 15:27
1
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
@Arne Good point, I just had a look in the source code ofpickleand it seems that the other attributes are dealt with by modifying__dict__directly whereas the slots use__setattr__. I'll take a deeper look and update.
– Jacques Gaudin
Mar 23 at 22:50
2
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
@drhagen Great, I'll try to compile withPyObject_GenericSetattrwhen I'll get a chance. Fingers crossed!
– Jacques Gaudin
Mar 25 at 16:40
I updated the previously deleted answer. It all boils down to creating your own
__setstate__ method to avoid a call to the instance's __setattr__.– Jacques Gaudin
Mar 23 at 15:27
I updated the previously deleted answer. It all boils down to creating your own
__setstate__ method to avoid a call to the instance's __setattr__.– Jacques Gaudin
Mar 23 at 15:27
1
1
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
do you know why it works if the class doesn't have slots? does it not use setattr to initialize in that case?
– Arne
Mar 23 at 22:29
@Arne Good point, I just had a look in the source code of
pickle and it seems that the other attributes are dealt with by modifying __dict__ directly whereas the slots use __setattr__. I'll take a deeper look and update.– Jacques Gaudin
Mar 23 at 22:50
@Arne Good point, I just had a look in the source code of
pickle and it seems that the other attributes are dealt with by modifying __dict__ directly whereas the slots use __setattr__. I'll take a deeper look and update.– Jacques Gaudin
Mar 23 at 22:50
2
2
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
I have reported this issue and recommended your workaround to the Python bug tracker. Hopefully, it will make it into the standard library.
– drhagen
Mar 25 at 15:22
@drhagen Great, I'll try to compile with
PyObject_GenericSetattr when I'll get a chance. Fingers crossed!– Jacques Gaudin
Mar 25 at 16:40
@drhagen Great, I'll try to compile with
PyObject_GenericSetattr when I'll get a chance. Fingers crossed!– Jacques Gaudin
Mar 25 at 16:40
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55307017%2fpickle-a-frozen-dataclass-that-has-slots%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown