Copy with __slots__

Alex Martelli aleax at
Wed Sep 18 22:56:17 CEST 2002

Christian Tismer wrote:
> You can get this to the single slot-level speed by doing
> the slot grabbing phase of above once, after the class

It's an important speed-up, yes -- but still quite a bit
slower than dealing with a single slot.

> speed can be found by not caching the __slots__ but their
> get/set wrappers and then just calling these with the new
> instance...

I've done that too (as a function, but would be trivial to
wrap as a custom metaclass):

class acceled(withslots):
    def __copy__(self):
        result = self.__class__.__new__(self.__class__)
        for get, set in self._accel:
            set(result, get(self))

def makeaccel(aclass):
    slot_names_seen = {}
    slot_gets_sets = []
    for base in aclass.__mro__:
        for s in getattr(base, '__slots__', []):
            if s in slot_names_seen: continue
            slot_names_seen[s] = True
            slot = getattr(base, s)
    aclass._accel = slot_gets_sets


[alex at lancelot ~]$ python -O
1.10 noslots
0.67 withslots
0.37 acceled
[alex at lancelot ~]$ python -O
1.14 noslots
0.69 withslots
0.37 acceled
[alex at lancelot ~]$ python -O
1.10 noslots
0.68 withslots
0.36 acceled

Not the 0.28 or so that I got by "unwrapping the loop" (i.e., just
coding out the assignment for each slot!), but still, an important
speedup, as I said.  Thanks on behalf of the OP!

It's not clear from the above what proportion of the gain is due
to just doing some of the work in advance, what to extracting
the getter and setter, what simply to avoidance of double work
that class withslots did because it copied attribute s1 twice.  As
the OP clearly needs practice in measuring Python runtimes (he
guessed that the 0.28 blazing-fast verson would be SLOWER
than the original 1.10 one, and didn't even THINK of doing a
measurement to double check his intuition...!!!), I guess I'll leave
this homework to him as a useful exercise:-).


More information about the Python-list mailing list