[Python-Dev] The Trick (was Re: copysort patch, was Re: inline sort option)

Alex Martelli aleaxit at yahoo.com
Sat Oct 18 08:26:39 EDT 2003


Wondering about the trick of copysort not copying a singly-referenced list I 
decided to try it out in a tiny extension module, and, yes, it is just as 
trivial as one might wish (haven't dealt with optional args to sort, just 
wanting to check performance &c):
static PyObject*
copysort(PyObject* self, PyObject* args)
{
 PyObject *sequence, *listresult;
 if(!PyArg_ParseTuple(args, "O", &sequence))
 return 0;
 if(PyList_CheckExact(sequence) && sequence->ob_refcnt==1) {
 listresult = sequence;
 Py_INCREF(listresult);
 } else {
 listresult = PySequence_List(sequence);
 }
 if(listresult) {
 if(PyList_Sort(listresult) == -1) {
 Py_DECREF(listresult);
 listresult = 0;
 }
 }
 return listresult;
}
and performance on an equally trivial testcase:
x = dict.fromkeys(range(99999))
def looponsorted1(x):
 keys = x.keys()
 keys.sort()
 for k in keys: pass
def looponsorted2(x, c=copysort.copysort):
 for k in c(x.keys()): pass
turns out to be identical between the two _with_ The Trick (4.4e+04 usec with 
timeit.py -c on my box) while without The Trick copysort would slow down to
about 5.5e+04 usec.
But, this reminds me -- function filter, in bltinmodule.c, uses just about the 
same trick too (to modify in-place when possible rather than making a new 
list -- even though when it does make a new list it's an empty one, not a
copy, so the gain is less). There must be other cases of applicability which
just haven't been considered. So...
Shouldn't The Trick be embodied in PySequence_List itself...? So, the whole 
small tricky part above:
 if(PyList_CheckExact(sequence) && sequence->ob_refcnt==1) {
 listresult = sequence;
 Py_INCREF(listresult);
 } else {
 listresult = PySequence_List(sequence);
 }
would collapse to a single PySequence_List call -- *AND* potential calls from
Python code such as "x=list(somedict.keys())" might also be speeded up 
analogously...
[Such a call looks silly when shown like this, but in some cases one might not 
know, in polymorphic use, whether a method returns a new or potentially 
shared list, or other sequence, and a call to list() on the method's result 
then may be needed to ensure the right semantics in all cases].
Is there any hidden trap in The Trick that makes it unadvisable to insert it 
in PySequence_List? Can't think of any, but I'm sure y'all will let me know 
ASAP what if anything I have overlooked...;-).
One might even be tempted to reach down all the way to PyList_GetSlice, 
placing THERE The Trick in cases of all-list slicing of a singly-referenced 
list (PyList_GetSlice is what PySequence_List uses, so it would also get the 
benefit), but that might be overdoing it -- and encouraging list(xxx) instead
of xxx[:], by making the former a bit faster in some cases, would be no bad 
thing IMHO (already I'm teaching newbies to prefer using list(...) rather 
than ...[:] strictly for legibility and clarity, being able to mention 
possible future performance benefits might well reinforce the habit...;-).
Alex


More information about the Python-Dev mailing list

AltStyle によって変換されたページ (->オリジナル) /