__slots_ and inheritance

Alexander Schmolck a.schmolck at gmx.net
Thu Apr 10 17:46:05 EDT 2003


Jim Meyer <jmeyer at pdi.com> writes:

> On Thu, 2003-04-10 at 06:39, Alexander Schmolck wrote:
> > I'd recommend against using __slots__ (unless really needed for optimization),
> > because it cripples the usefulness and generality of your classes to your and
> > also *to other people's* code (weakrefs, pickling, reflection -- all
> > compromised). The first two you could fix (but are unlikely to, unless you
> > *yourself* need to use weakrefs or pickling of instances of those classes),
> > the last one you can't.
> 
> I'm feeling very slow this morning; could you give a few explicit
> examples of how __slots__ interferes with weakrefs, pickling, and
> reflection?

class Normal(object): pass
class Normal2(object): pass    
class A(object):
    __slots__ = 'slot_a slot_b'.split()
    
class B(object):
    __slots__ = 'slot_a slot_b'.split()

>>> n = Normal()
>>> vars(n)
>>> n.__class__ = Normal2
>>> n
<__main__.Normal2 object at 0x8c7df6c>
>>> weakref.ref(n)
<weakref at 0x8b89154; to 'Normal2' at 0x8c7df6c>


now let's try with __slots__

{'slot_a': 23}
>>> a = A()
>>> vars(a)
TypeError: vars() argument must have __dict__ attribute
>>> a.__class__ = B
TypeError: __class__ assignment: 'B' object layout differs from 'A'
>>> weakref.ref(a)
TypeError: cannot create weak reference to 'A' object

(same for pickling)

maybe we *could* find out about a by looking at a.__slots__?

class A(object):
    __slots__ = 'slot_a slot_b'.split()
A.__slots__ = 'a b'.split()
>>> a = A()
>>> a.__slots__
['a', 'b']
>>> a.a = 1
AttributeError: 'A' object has no attribute 'a'
>>> a.slot_a = 1

Fun, isn't it?

And there is yet more fun:


"You cannot use a class attribute to define a default value for an instance
 variable defined by __slots__."


"If a class defines a slot that's also defined in a base class, the instance
 variable defined by the base class slot is inaccessible (except by retrieving
 its descriptor directly from the base class; this could be used to rename it).
 Doing this renders the meaning of your program undefined"

The real purpose is apparently efficiency but if so, it is remarkably ill
conceived. The main person who should have to pay for efficiency features is
the one who writes a particular piece of code that uses them, not others. And
if he imposes a burden on others, it should be quite clear to him and not too
onerous a burden either.

With __slots__ none of this holds true. I bet most people will want to use
__slots__ to catch typos (which seems attractive enough), as did Paul Rubin,
presumably without realizing at all the ill effects of using __slots__. So
mostly they won't bother making their classes pickleable or weakrefable. In
consequence you'll have plenty of code around that needlessly breaks, cripples
or at the very least complicates, other code, largely because people blithly
use some dubious "feature", most likely for the wrong reasons and without
understanding the consequences.

Fundamental reflective capabilities, simplicity and cleanness of the language
are all compromised, just for some silly efficiency gain.


'as





More information about the Python-list mailing list