Another reason to avoid using __slots__ in your Python classes

April 19, 2011

Presented in the traditional illustrated form:

class A(object):
     __slots__ = ('a',)

class B1(A):
     __slots__ = ('b1',)

class B2(A):
     __slots__ = ('b2',)

Now try to define a class C that inherits from both B1 and B2, and you will get:

TypeError: Error when calling the metaclass bases
   multiple bases have instance lay-out conflict

It's relatively intuitive to see why and how this conflict happens at an abstract level. Imagine that __slots__ fields are sort of like function local variables and go in an indexed array. Then class A uses the first array slot for a, and class B1 and B2 both use the second array slot for b1 and b2 respectively. When you get to C, you have a conflict; the second array slot is used twice.

It is apparently popular in certain circles to use __slots__ just to make it so that class instances can't have extra attributes added to them at runtime. The example here illustrates the problem with this; using __slots__ has effects on what you or other people can do later with the classes.

Sidebar: about those variable names

Update: I am wrong about what I wrote below, because it turns out that a little knowledge is a dangerous thing. Per the Python data model documentation on slots, a class without a __slots__ definition turns off slots entirely, so the example below isn't doing what I think it's doing. Oops.

As it turns out, you can't avoid this conflict by giving the instance variable the same name in B1 and B2. If it really is the same variable, you need to introduce a parent B class that defines it:

class B(A):
     __slots__ = ('b',)

class B1(B):
     pass

class B2(B):
     pass

Then you can define a class C that inherits from both B1 and B2.

Written on 19 April 2011.
« A difference between Python 'structs' and C structs
How CPython implements __slots__ (part 1): storage »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Tue Apr 19 13:38:10 2011
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.