Question about consistency in python language

Kay Schluehr kay.schluehr at gmx.net
Sun Sep 11 06:01:09 EDT 2005


Steve Holden wrote:
> Kay Schluehr wrote:
> > Mike Meyer wrote:
> >
> >
> >>Yes, but the function "sorted" is more useful than a list method
> >>"sorted" in a duck typing language.
> >
> >
> > I don't see what this has to do with "duck typing"? sorted() is simply
> > a generic function accepting different types. I'm not aware that
> > sorted() requires a specific interface of those types it accepts.
> >
> Just because you aren't aware of something doesn't stop it being true.
> The argument must be iterable, and there's a specific protocol for that.
> >
> >>The function sorted works on all iterators. I can do:
> >>
> Ah, so you *were* aware of it.

I already responded to it two days ago in the reply to Terry. No need
to rehash that.

> >>
> >>>>>def t(n):
> >>>>>  for i in range(n):
> >>>>>    yield i
> >>>>>...
> >>>>>print sorted(t(5))
> >>
> >>and have it work.
> >>
> >>If sorted were a method of a class - the it'd have to be implemented
> >>again for every class iterable class. Either that, or you'd have to
> >>create an abstract parent of all iterable classes to add it to - which
> >>seems more appropriate for a B&D language than Python.
> >
> >
> > Instead of extending a class hierarchy it might even be possible to
> > hook a trait into the class by means of a __traits__ attribute.
> >
> > http://fsl.cs.uiuc.edu/~mhills/presentations/TraitsPresentation.pdf
> >
> > Generators as well as lists and tuples would provide a sortable trait.
> > The sorted() function could remain available for convenience.
> >
> The advantage being ... ? Perhaps you have just discovered a really
> interesting hammer, and are seeing this problem as a nail?

I also responded to traits as nice-to-have but not essential. And
please don't aggressively consider me as childish as you might be
yourself.

Adding a __traits__ attribute should enable the user adding methods to
builtins in a safe manner. This has the advantage that one can apply
methods to string or integer literals or even replace methods without
touching the C sources. A very typical use case is integer
representation. In 95% of all my business applications I don't have
much use for decimal integer representation but want a hex rep in
different variants:

>>> 0x0F  # current rep
15

>>> int.__traits__.append(HexRepTrait)  # used for delegation of
                                        # __repr__ to the Trait
>>> int.configure_format(HexRepTrait.HEXFORM_STD) # configure_format is a
                                                  # hooked trait method
>>> 0x0F
0F
>>> 2*0x800
10 00
>>> print 700
02 BC

I know I can write wrapper classes, because I do this all the time, but
that's not the point: Python is essentially not about boiler-plate. And
no, I also don't want to fight for each method and keyword with Guido.

> >
> >>And even if you do add the abstract class, how do you make my example
> >>work without explictly converting the iterator to a list type?
> >
> >
> > I don't know how sorted() is implemented? A naive implementation would
> > in fact be nothing else then:
> >
> > def sorted(iter):
> >     l = list(iter)
> >     l.sort()
> >     return l
> >
> > Kay
> >
> That would indeed be a naïve implementation.

And that's the real implementation:

static PyObject *
builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds)
{
	PyObject *newlist, *v, *seq, *compare=NULL, *keyfunc=NULL, *newargs;
	PyObject *callable;
	static char *kwlist[] = {"iterable", "cmp", "key", "reverse", 0};
	long reverse;

	if (args != NULL) {
		if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OOi:sorted",
			kwlist, &seq, &compare, &keyfunc, &reverse))
			return NULL;
	}

	newlist = PySequence_List(seq);
	if (newlist == NULL)
		return NULL;

	callable = PyObject_GetAttrString(newlist, "sort");
	if (callable == NULL) {
		Py_DECREF(newlist);
		return NULL;
	}

	newargs = PyTuple_GetSlice(args, 1, 4);
	if (newargs == NULL) {
		Py_DECREF(newlist);
		Py_DECREF(callable);
		return NULL;
	}

	v = PyObject_Call(callable, newargs, kwds);
	Py_DECREF(newargs);
	Py_DECREF(callable);
	if (v == NULL) {
		Py_DECREF(newlist);
		return NULL;
	}
	Py_DECREF(v);
	return newlist;
}


The crucial steps are the conversion from args to seq, the conversion
from seq to newlist and finally calling PyObject_Call(callable, ...)
where callable stores the sort method of newlist. By the way I don't
see much use in implementing this trivial wrapper function in C except
for the joy of refcounting ;)

And now we take a look on how the PyPythonistas implemented sorted():

def sorted(lst, cmp=None, key=None, reverse=None):
    "sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted
list"
    sorted_lst = list(lst)
    sorted_lst.sort(cmp, key, reverse)
    return sorted_lst

Surprise, surprise!

> The implementation is, of
> course, an implementation detail ;-) In this case it requires that
> sort() then provides all the magic - the need for magic doesn't go away!

Has anyone denied the necessaty of sort()? 

Kay




More information about the Python-list mailing list