[Python-ideas] add a list.swap() method
Steven D'Aprano
steve at pearwood.info
Wed Jun 24 02:19:45 CEST 2009
On Wed, 24 Jun 2009 06:23:31 am Kristján Valur Jónsson wrote:
> Hello there.
> Please see my feature request: http://bugs.python.org/issue6326
>
> The idea is to speed up the swapping of list elemenst so that
> a.swap(b)
> is equivalent to
> a[:], b[:] = b[:], a[:]
> but without all the overhead of creating slices, assigning them and
> so forth. In particular, it can help reduce the cost of creating
> instances of list subclasses, from raw lists:
>
> class mylist(list):
> def first(self):
> return self[0]
>
> m = mylist(source_list)
Is that overhead really significant enough that it needs a special
operation to avoid it? In the tracker, you claim a significant
performance gain, but I'd like to hear more details.
> This certainly creates m, but does so by copying source_list.
Only the pointers, not the objects pointed to. But I'm sure you already
know this :)
> If all
> we want to do is turn source_list into a mylist instance, it is much
> quicker to: m = mylist()
> m.swap(source_list)
This has a side-effect of turning source_list into an empty mylist. I
don't like that one bit.
> See the above issue for initial comments, especially concerns on how
> this can bypass all kind of insertion semantics of list subclasses.
Can you address those concerns?
One problem with swap() being a list method is that it allows people to
arbitrarily swap the contents of lists around, breaking subclass
invariants. I have an alternative suggestion: put the swap into
list.__new__, so it can only be done at list initialisation time.
list.__new__(cls, source) currently returns an empty list of type cls,
which is then initialised by list.__init__(self, source), presumably by
copying source. Perhaps list.__new__ could take an additional argument
that says "swap the contents of the new list to use source without
copying".
That means, instead of writing:
a = mylist()
a.swap([1, 2, 3])
you would put the fast initialisation logic into the class:
class mylist(list):
def __new__(cls, source):
return list.__new__(cls, source, swap=True)
def __init__(self, source):
pass # avoid calling list.__init__
Existing code should work unchanged if the default for swap is False.
--
Steven D'Aprano
More information about the Python-ideas
mailing list