Python3, __slots__ and serialization

E

Eric Jacoboni

Hi,

Say i want create a class with a __slots__ tuple in order to prevent
creation of new attributes from outside the class.

Say i want to serialize instances of this class... With pickle, all is
ok : i can dump an object to a file, then reload it.

With PyYAML, i can dump an object to a file, but trying to reload it fails.

If i comment out the __slots__ tuple, all is fine but, then, the class
is "open"... Is there some magic to have both a __slots__ tuple and a
working yaml.load() ?
 
N

Ned Batchelder

Hi,

Say i want create a class with a __slots__ tuple in order to prevent
creation of new attributes from outside the class.

Say i want to serialize instances of this class... With pickle, all is
ok : i can dump an object to a file, then reload it.

With PyYAML, i can dump an object to a file, but trying to reload it fails.

If i comment out the __slots__ tuple, all is fine but, then, the class
is "open"... Is there some magic to have both a __slots__ tuple and a
working yaml.load() ?

Preventing attribute creation runs counter to Python's philosophy, so it
doesn't surprise me that it causes problems. There might be a way to
make it all work together, but I don't know.

__slots__ wasn't meant to be a way to prevent attribute creation, it was
meant as a way to save space by avoiding the need for an attributes
dictionary.

Why do you need to prevent attribute creation? If someone uses your
class and wants to use it in ways you didn't anticipate, why should you
try to stop them?
 
N

Ned Batchelder

Preventing attribute creation runs counter to Python's philosophy, so it
doesn't surprise me that it causes problems. There might be a way to
make it all work together, but I don't know.

__slots__ wasn't meant to be a way to prevent attribute creation, it was
meant as a way to save space by avoiding the need for an attributes
dictionary.

Why do you need to prevent attribute creation? If someone uses your
class and wants to use it in ways you didn't anticipate, why should you
try to stop them?

I also looked at why it fails. I get this error:


Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/__init__.py",
line 71, in load
return loader.get_single_data()
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/constructor.py",
line 39, in get_single_data
return self.construct_document(node)
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/constructor.py",
line 43, in construct_document
data = self.construct_object(node)
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/constructor.py",
line 90, in construct_object
data = constructor(self, tag_suffix, node)
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/constructor.py",
line 610, in construct_python_object_new
return self.construct_python_object_apply(suffix, node, newobj=True)
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/constructor.py",
line 601, in construct_python_object_apply
self.set_python_instance_state(instance, state)
File
"/usr/local/virtualenvs/lab/lib/python2.7/site-packages/yaml/constructor.py",
line 563, in set_python_instance_state
setattr(object, key, value)
TypeError: can't set attributes of built-in/extension type 'object'

This is set_python_instance_state, the failing code:

def set_python_instance_state(self, instance, state):
if hasattr(instance, '__setstate__'):
instance.__setstate__(state)
else:
slotstate = {}
if isinstance(state, tuple) and len(state) == 2:
state, slotstate = state
if hasattr(instance, '__dict__'):
instance.__dict__.update(state)
elif state:
slotstate.update(state)
for key, value in slotstate.items():
setattr(object, key, value)

Two things seem clear to me: 1) you can define __setstate__ to do what
you need to do, and 2) this code is simply wrong. The last line should
use "instance", not "object", and it might be that the last two lines
should really be indented withing the elif.

All that said, skip __slots__: it isn't helping you with any actual
problem, and it's forcing you to jump through hoops, or run code that
most Python programs don't run.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top