Guido grants a Christmas wish:

sorted() becomes a regular function instead of a classmethod.
This commit is contained in:
Raymond Hettinger 2003-12-17 20:43:33 +00:00
parent df38ea9c29
commit 64958a15d7
15 changed files with 120 additions and 138 deletions

View file

@ -886,6 +886,15 @@ class C(object):
\samp{a[start:stop, i]}. \samp{a[start:stop, i]}.
\end{funcdesc} \end{funcdesc}
\begin{funcdesc}{sorted(\var{iterable}\optional{, \var{cmp}=None
\optional{, \var{key}=None
\optional{, \var{reverse}=False}}})}
Return a new sorted list from the items in \var{iterable}.
The optional arguments \var{cmp}, \var{key}, and \var{reverse}
have the same meaning as those for the \method{list.sort()} method.
\versionadded{2.4}
\end{funcdesc}
\begin{funcdesc}{staticmethod}{function} \begin{funcdesc}{staticmethod}{function}
Return a static method for \var{function}. Return a static method for \var{function}.

View file

@ -398,7 +398,7 @@ Samuele
# Show a dictionary sorted and grouped by value # Show a dictionary sorted and grouped by value
>>> from operator import itemgetter >>> from operator import itemgetter
>>> d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3) >>> d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3)
>>> di = list.sorted(d.iteritems(), key=itemgetter(1)) >>> di = sorted(d.iteritems(), key=itemgetter(1))
>>> for k, g in groupby(di, key=itemgetter(1)): >>> for k, g in groupby(di, key=itemgetter(1)):
... print k, map(itemgetter(0), g) ... print k, map(itemgetter(0), g)
... ...

View file

@ -988,9 +988,6 @@ The following operations are defined on mutable sequence types (where
\lineiii{\var{s}.sort(\optional{\var{cmp}=None\optional{, \var{key}=None \lineiii{\var{s}.sort(\optional{\var{cmp}=None\optional{, \var{key}=None
\optional{, \var{reverse}=False}}})} \optional{, \var{reverse}=False}}})}
{sort the items of \var{s} in place}{(7), (8), (9), (10)} {sort the items of \var{s} in place}{(7), (8), (9), (10)}
\lineiii{\var{s}.sorted(\var{iterable}\optional{, \var{cmp}=None\optional{, \var{key}=None
\optional{, \var{reverse}=False}}})}
{return a new sorted list from the items in \var{iterable}}{(8), (9), (11)}
\end{tableiii} \end{tableiii}
\indexiv{operations on}{mutable}{sequence}{types} \indexiv{operations on}{mutable}{sequence}{types}
\indexiii{operations on}{sequence}{types} \indexiii{operations on}{sequence}{types}
@ -1040,8 +1037,8 @@ Notes:
list. To remind you that they operate by side effect, they don't return list. To remind you that they operate by side effect, they don't return
the sorted or reversed list. the sorted or reversed list.
\item[(8)] The \method{sort()} and \method{sorted()} methods take optional \item[(8)] The \method{sort()} method takes optional arguments for
arguments for controlling the comparisons. controlling the comparisions.
\var{cmp} specifies a custom comparison function of two arguments \var{cmp} specifies a custom comparison function of two arguments
(list items) which should return a negative, zero or positive number (list items) which should return a negative, zero or positive number
@ -1068,8 +1065,7 @@ Notes:
\versionchanged[Support for \var{key} and \var{reverse} was added]{2.4} \versionchanged[Support for \var{key} and \var{reverse} was added]{2.4}
\item[(9)] Starting with Python 2.3, the \method{sort()} method is \item[(9)] Starting with Python 2.3, the \method{sort()} method is
guaranteed to be stable. Starting with Python 2.4, the \method{sorted()} guaranteed to be stable. A sort is stable if it guarantees not to
method is also guaranteed to be stable. A sort is stable if it does not
change the relative order of elements that compare equal --- this is change the relative order of elements that compare equal --- this is
helpful for sorting in multiple passes (for example, sort by helpful for sorting in multiple passes (for example, sort by
department, then by salary grade). department, then by salary grade).
@ -1079,9 +1075,6 @@ Notes:
of Python 2.3 makes the list appear empty for the duration, and raises of Python 2.3 makes the list appear empty for the duration, and raises
\exception{ValueError} if it can detect that the list has been \exception{ValueError} if it can detect that the list has been
mutated during a sort. mutated during a sort.
\item[(11)] \method{sorted()} is a class method that returns a new list.
\versionadded{2.4}
\end{description} \end{description}
\subsection{Set Types \label{types-set}} \subsection{Set Types \label{types-set}}

View file

@ -177,9 +177,9 @@ they were input. For example, you can sort a list of people by name,
and then sort the list by age, resulting in a list sorted by age where and then sort the list by age, resulting in a list sorted by age where
people with the same age are in name-sorted order. people with the same age are in name-sorted order.
\item The list type gained a \method{sorted(iterable)} method that works \item There is a new builtin function \function{sorted(iterable)} that works
like the in-place \method{sort()} method but has been made suitable for like the in-place \method{list.sort()} method but has been made suitable
use in expressions. The differences are: for use in expressions. The differences are:
\begin{itemize} \begin{itemize}
\item the input may be any iterable; \item the input may be any iterable;
\item a newly formed copy is sorted, leaving the original intact; and \item a newly formed copy is sorted, leaving the original intact; and
@ -188,17 +188,17 @@ use in expressions. The differences are:
\begin{verbatim} \begin{verbatim}
>>> L = [9,7,8,3,2,4,1,6,5] >>> L = [9,7,8,3,2,4,1,6,5]
>>> [10+i for i in list.sorted(L)] # usable in a list comprehension >>> [10+i for i in sorted(L)] # usable in a list comprehension
[11, 12, 13, 14, 15, 16, 17, 18, 19] [11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> L = [9,7,8,3,2,4,1,6,5] # original is left unchanged >>> L = [9,7,8,3,2,4,1,6,5] # original is left unchanged
[9,7,8,3,2,4,1,6,5] [9,7,8,3,2,4,1,6,5]
>>> list.sorted('Monte Python') # any iterable may be an input >>> sorted('Monte Python') # any iterable may be an input
[' ', 'M', 'P', 'e', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y'] [' ', 'M', 'P', 'e', 'h', 'n', 'n', 'o', 'o', 't', 't', 'y']
>>> # List the contents of a dict sorted by key values >>> # List the contents of a dict sorted by key values
>>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5) >>> colormap = dict(red=1, blue=2, green=3, black=4, yellow=5)
>>> for k, v in list.sorted(colormap.iteritems()): >>> for k, v in sorted(colormap.iteritems()):
... print k, v ... print k, v
... ...
black 4 black 4
@ -301,14 +301,14 @@ counting, or identifying duplicate elements:
\begin{verbatim} \begin{verbatim}
>>> word = 'abracadabra' >>> word = 'abracadabra'
>>> word = list.sorted(word) # Turn string into sorted list of letters >>> letters = sorted(word) # Turn string into sorted list of letters
>>> word >>> letters
['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r'] ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'c', 'd', 'r', 'r']
>>> [k for k, g in groupby(word)] # List the various group keys >>> [k for k, g in groupby(word)] # List unique letters
['a', 'b', 'c', 'd', 'r'] ['a', 'b', 'c', 'd', 'r']
>>> [(k, len(list(g))) for k, g in groupby(word)] # List key and group length >>> [(k, len(list(g))) for k, g in groupby(word)] # Count letter occurences
[('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)] [('a', 5), ('b', 2), ('c', 1), ('d', 1), ('r', 2)]
>>> [k for k, g in groupby(word) if len(list(g)) > 1] # All groups of size >1 >>> [k for k, g in groupby(word) if len(list(g)) > 1] # List duplicate letters
['a', 'b', 'r'] ['a', 'b', 'r']
\end{verbatim} \end{verbatim}

View file

@ -78,11 +78,6 @@ class UserList:
def index(self, item, *args): return self.data.index(item, *args) def index(self, item, *args): return self.data.index(item, *args)
def reverse(self): self.data.reverse() def reverse(self): self.data.reverse()
def sort(self, *args, **kwds): self.data.sort(*args, **kwds) def sort(self, *args, **kwds): self.data.sort(*args, **kwds)
def sorted(cls, iterable, *args, **kwds):
s = cls(iterable)
s.sort(*args, **kwds)
return s
sorted = classmethod(sorted)
def extend(self, other): def extend(self, other):
if isinstance(other, UserList): if isinstance(other, UserList):
self.data.extend(other.data) self.data.extend(other.data)

View file

@ -327,7 +327,7 @@ def _main():
for obj in objs: for obj in objs:
if isinstance(obj, Class): if isinstance(obj, Class):
print "class", obj.name, obj.super, obj.lineno print "class", obj.name, obj.super, obj.lineno
methods = list.sorted(obj.methods.iteritems(), key=itemgetter(1)) methods = sorted(obj.methods.iteritems(), key=itemgetter(1))
for name, lineno in methods: for name, lineno in methods:
if name != "__path__": if name != "__path__":
print " def", name, lineno print " def", name, lineno

View file

@ -3,7 +3,7 @@
import test.test_support, unittest import test.test_support, unittest
from test.test_support import fcmp, have_unicode, TESTFN, unlink from test.test_support import fcmp, have_unicode, TESTFN, unlink
import sys, warnings, cStringIO import sys, warnings, cStringIO, random
warnings.filterwarnings("ignore", "hex../oct.. of negative int", warnings.filterwarnings("ignore", "hex../oct.. of negative int",
FutureWarning, __name__) FutureWarning, __name__)
warnings.filterwarnings("ignore", "integer argument expected", warnings.filterwarnings("ignore", "integer argument expected",
@ -1153,8 +1153,41 @@ class BuiltinTest(unittest.TestCase):
return i return i
self.assertRaises(ValueError, zip, BadSeq(), BadSeq()) self.assertRaises(ValueError, zip, BadSeq(), BadSeq())
class TestSorted(unittest.TestCase):
def test_basic(self):
data = range(100)
copy = data[:]
random.shuffle(copy)
self.assertEqual(data, sorted(copy))
self.assertNotEqual(data, copy)
data.reverse()
random.shuffle(copy)
self.assertEqual(data, sorted(copy, cmp=lambda x, y: cmp(y,x)))
self.assertNotEqual(data, copy)
random.shuffle(copy)
self.assertEqual(data, sorted(copy, key=lambda x: -x))
self.assertNotEqual(data, copy)
random.shuffle(copy)
self.assertEqual(data, sorted(copy, reverse=1))
self.assertNotEqual(data, copy)
def test_inputtypes(self):
s = 'abracadabra'
for T in [unicode, list, tuple]:
self.assertEqual(sorted(s), sorted(T(s)))
s = ''.join(dict.fromkeys(s).keys()) # unique letters only
for T in [unicode, set, frozenset, list, tuple, dict.fromkeys]:
self.assertEqual(sorted(s), sorted(T(s)))
def test_baddecorator(self):
data = 'The quick Brown fox Jumped over The lazy Dog'.split()
self.assertRaises(TypeError, sorted, data, None, lambda x,y: 0)
def test_main(): def test_main():
test.test_support.run_unittest(BuiltinTest) test.test_support.run_unittest(BuiltinTest, TestSorted)
if __name__ == "__main__": if __name__ == "__main__":
test_main() test_main()

View file

@ -226,8 +226,7 @@ Instead, you can get the same information from the list type:
'pop', 'pop',
'remove', 'remove',
'reverse', 'reverse',
'sort', 'sort']
'sorted']
The new introspection API gives more information than the old one: in The new introspection API gives more information than the old one: in
addition to the regular methods, it also shows the methods that are addition to the regular methods, it also shows the methods that are

View file

@ -97,16 +97,16 @@ class TestBasicOps(unittest.TestCase):
# Exercise pipes and filters style # Exercise pipes and filters style
s = 'abracadabra' s = 'abracadabra'
# sort s | uniq # sort s | uniq
r = [k for k, g in groupby(list.sorted(s))] r = [k for k, g in groupby(sorted(s))]
self.assertEqual(r, ['a', 'b', 'c', 'd', 'r']) self.assertEqual(r, ['a', 'b', 'c', 'd', 'r'])
# sort s | uniq -d # sort s | uniq -d
r = [k for k, g in groupby(list.sorted(s)) if list(islice(g,1,2))] r = [k for k, g in groupby(sorted(s)) if list(islice(g,1,2))]
self.assertEqual(r, ['a', 'b', 'r']) self.assertEqual(r, ['a', 'b', 'r'])
# sort s | uniq -c # sort s | uniq -c
r = [(len(list(g)), k) for k, g in groupby(list.sorted(s))] r = [(len(list(g)), k) for k, g in groupby(sorted(s))]
self.assertEqual(r, [(5, 'a'), (2, 'b'), (1, 'c'), (1, 'd'), (2, 'r')]) self.assertEqual(r, [(5, 'a'), (2, 'b'), (1, 'c'), (1, 'd'), (2, 'r')])
# sort s | uniq -c | sort -rn | head -3 # sort s | uniq -c | sort -rn | head -3
r = list.sorted([(len(list(g)) , k) for k, g in groupby(list.sorted(s))], reverse=True)[:3] r = sorted([(len(list(g)) , k) for k, g in groupby(sorted(s))], reverse=True)[:3]
self.assertEqual(r, [(5, 'a'), (2, 'r'), (2, 'b')]) self.assertEqual(r, [(5, 'a'), (2, 'r'), (2, 'b')])
# iter.next failure # iter.next failure
@ -669,7 +669,7 @@ Samuele
>>> from operator import itemgetter >>> from operator import itemgetter
>>> d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3) >>> d = dict(a=1, b=2, c=1, d=2, e=1, f=2, g=3)
>>> di = list.sorted(d.iteritems(), key=itemgetter(1)) >>> di = sorted(d.iteritems(), key=itemgetter(1))
>>> for k, g in groupby(di, itemgetter(1)): >>> for k, g in groupby(di, itemgetter(1)):
... print k, map(itemgetter(0), g) ... print k, map(itemgetter(0), g)
... ...

View file

@ -263,7 +263,7 @@ class OperatorTestCase(unittest.TestCase):
inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)] inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)]
getcount = operator.itemgetter(1) getcount = operator.itemgetter(1)
self.assertEqual(map(getcount, inventory), [3, 2, 5, 1]) self.assertEqual(map(getcount, inventory), [3, 2, 5, 1])
self.assertEqual(list.sorted(inventory, key=getcount), self.assertEqual(sorted(inventory, key=getcount),
[('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)]) [('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)])
def test_main(): def test_main():

View file

@ -22,8 +22,8 @@ class TestJointOps(unittest.TestCase):
self.d = dict.fromkeys(word) self.d = dict.fromkeys(word)
def test_uniquification(self): def test_uniquification(self):
actual = list.sorted(self.s) actual = sorted(self.s)
expected = list.sorted(self.d) expected = sorted(self.d)
self.assertEqual(actual, expected) self.assertEqual(actual, expected)
self.assertRaises(PassThru, self.thetype, check_pass_thru()) self.assertRaises(PassThru, self.thetype, check_pass_thru())
self.assertRaises(TypeError, self.thetype, [[]]) self.assertRaises(TypeError, self.thetype, [[]])
@ -1241,7 +1241,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
for cons in (set, frozenset): for cons in (set, frozenset):
for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)): for s in ("123", "", range(1000), ('do', 1.2), xrange(2000,2200,5)):
for g in (G, I, Ig, S, L, R): for g in (G, I, Ig, S, L, R):
self.assertEqual(list.sorted(cons(g(s))), list.sorted(g(s))) self.assertEqual(sorted(cons(g(s))), sorted(g(s)))
self.assertRaises(TypeError, cons , X(s)) self.assertRaises(TypeError, cons , X(s))
self.assertRaises(TypeError, cons , N(s)) self.assertRaises(TypeError, cons , N(s))
self.assertRaises(ZeroDivisionError, cons , E(s)) self.assertRaises(ZeroDivisionError, cons , E(s))
@ -1253,7 +1253,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
for g in (G, I, Ig, L, R): for g in (G, I, Ig, L, R):
expected = meth(data) expected = meth(data)
actual = meth(G(data)) actual = meth(G(data))
self.assertEqual(list.sorted(actual), list.sorted(expected)) self.assertEqual(sorted(actual), sorted(expected))
self.assertRaises(TypeError, meth, X(s)) self.assertRaises(TypeError, meth, X(s))
self.assertRaises(TypeError, meth, N(s)) self.assertRaises(TypeError, meth, N(s))
self.assertRaises(ZeroDivisionError, meth, E(s)) self.assertRaises(ZeroDivisionError, meth, E(s))
@ -1267,7 +1267,7 @@ class TestVariousIteratorArgs(unittest.TestCase):
t = s.copy() t = s.copy()
getattr(s, methname)(list(g(data))) getattr(s, methname)(list(g(data)))
getattr(t, methname)(g(data)) getattr(t, methname)(g(data))
self.assertEqual(list.sorted(s), list.sorted(t)) self.assertEqual(sorted(s), sorted(t))
self.assertRaises(TypeError, getattr(set('january'), methname), X(data)) self.assertRaises(TypeError, getattr(set('january'), methname), X(data))
self.assertRaises(TypeError, getattr(set('january'), methname), N(data)) self.assertRaises(TypeError, getattr(set('january'), methname), N(data))

View file

@ -248,66 +248,11 @@ class TestDecorateSortUndecorate(unittest.TestCase):
copy2.sort(key=lambda x: x[0], reverse=True) copy2.sort(key=lambda x: x[0], reverse=True)
self.assertEqual(data, copy2) self.assertEqual(data, copy2)
class TestSorted(unittest.TestCase):
def test_basic(self):
data = range(100)
copy = data[:]
random.shuffle(copy)
self.assertEqual(data, list.sorted(copy))
self.assertNotEqual(data, copy)
data.reverse()
random.shuffle(copy)
self.assertEqual(data, list.sorted(copy, cmp=lambda x, y: cmp(y,x)))
self.assertNotEqual(data, copy)
random.shuffle(copy)
self.assertEqual(data, list.sorted(copy, key=lambda x: -x))
self.assertNotEqual(data, copy)
random.shuffle(copy)
self.assertEqual(data, list.sorted(copy, reverse=1))
self.assertNotEqual(data, copy)
def test_inputtypes(self):
s = 'abracadabra'
for T in [unicode, list, tuple]:
self.assertEqual(list.sorted(s), list.sorted(T(s)))
s = ''.join(dict.fromkeys(s).keys()) # unique letters only
for T in [unicode, set, frozenset, list, tuple, dict.fromkeys]:
self.assertEqual(list.sorted(s), list.sorted(T(s)))
def test_baddecorator(self):
data = 'The quick Brown fox Jumped over The lazy Dog'.split()
self.assertRaises(TypeError, list.sorted, data, None, lambda x,y: 0)
def classmethods(self):
s = "hello world"
a = list.sorted(s)
b = UserList.sorted(s)
c = [].sorted(s)
d = UserList().sorted(s)
class Mylist(list):
def __new__(cls):
return UserList()
e = MyList.sorted(s)
f = MyList().sorted(s)
class Myuserlist(UserList):
def __new__(cls):
return []
g = MyList.sorted(s)
h = MyList().sorted(s)
self.assert_(a == b == c == d == e == f == g == h)
self.assert_(b.__class__ == d.__class__ == UserList)
self.assert_(e.__class__ == f.__class__ == MyList)
self.assert_(g.__class__ == h.__class__ == Myuserlist)
#============================================================================== #==============================================================================
def test_main(verbose=None): def test_main(verbose=None):
test_classes = ( test_classes = (
TestDecorateSortUndecorate, TestDecorateSortUndecorate,
TestSorted,
TestBugs, TestBugs,
) )

View file

@ -75,6 +75,9 @@ Core and builtins
- Added a reversed() builtin function that returns a reverse iterator - Added a reversed() builtin function that returns a reverse iterator
over a sequence. over a sequence.
- Added a sorted() builtin function that returns a new sorted list
from any iterable.
- CObjects are now mutable (on the C level) through PyCObject_SetVoidPtr. - CObjects are now mutable (on the C level) through PyCObject_SetVoidPtr.
- list.sort() now supports three keyword arguments: cmp, key, and reverse. - list.sort() now supports three keyword arguments: cmp, key, and reverse.
@ -86,9 +89,6 @@ Core and builtins
starting with Py2.3 are guaranteed to be stable (the relative order of starting with Py2.3 are guaranteed to be stable (the relative order of
records with equal keys is unchanged). records with equal keys is unchanged).
- Added a list.sorted() classmethod that returns a new sorted list
from any iterable.
- Added test whether wchar_t is signed or not. A signed wchar_t is not - Added test whether wchar_t is signed or not. A signed wchar_t is not
usable as internal unicode type base for Py_UNICODE since the usable as internal unicode type base for Py_UNICODE since the
unicode implementation assumes an unsigned type. unicode implementation assumes an unsigned type.

View file

@ -2020,38 +2020,6 @@ PyList_Sort(PyObject *v)
return 0; return 0;
} }
static PyObject *
listsorted(PyObject *cls, PyObject *args, PyObject *kwds)
{
PyObject *newlist, *v, *seq, *compare=NULL, *keyfunc=NULL, *newargs;
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 = PyObject_CallFunctionObjArgs(cls, seq, NULL);
if (newlist == NULL)
return NULL;
newargs = PyTuple_GetSlice(args, 1, 4);
if (newargs == NULL) {
Py_DECREF(newlist);
return NULL;
}
v = listsort((PyListObject *)newlist, newargs, kwds);
Py_DECREF(newargs);
if (v == NULL) {
Py_DECREF(newlist);
return NULL;
}
Py_DECREF(v);
return newlist;
}
static PyObject * static PyObject *
listreverse(PyListObject *self) listreverse(PyListObject *self)
{ {
@ -2394,9 +2362,6 @@ PyDoc_STRVAR(reverse_doc,
PyDoc_STRVAR(sort_doc, PyDoc_STRVAR(sort_doc,
"L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;\n\ "L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;\n\
cmp(x, y) -> -1, 0, 1"); cmp(x, y) -> -1, 0, 1");
PyDoc_STRVAR(sorted_doc,
"list.sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list;\n\
cmp(x, y) -> -1, 0, 1");
static PyObject *list_subscript(PyListObject*, PyObject*); static PyObject *list_subscript(PyListObject*, PyObject*);
@ -2412,8 +2377,6 @@ static PyMethodDef list_methods[] = {
{"count", (PyCFunction)listcount, METH_O, count_doc}, {"count", (PyCFunction)listcount, METH_O, count_doc},
{"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc}, {"reverse", (PyCFunction)listreverse, METH_NOARGS, reverse_doc},
{"sort", (PyCFunction)listsort, METH_VARARGS | METH_KEYWORDS, sort_doc}, {"sort", (PyCFunction)listsort, METH_VARARGS | METH_KEYWORDS, sort_doc},
{"sorted", (PyCFunction)listsorted,
METH_VARARGS | METH_KEYWORDS | METH_CLASS, sorted_doc},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };

View file

@ -1758,6 +1758,50 @@ PyDoc_STRVAR(round_doc,
Round a number to a given precision in decimal digits (default 0 digits).\n\ Round a number to a given precision in decimal digits (default 0 digits).\n\
This always returns a floating point number. Precision may be negative."); This always returns a floating point number. Precision may be negative.");
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;
}
PyDoc_STRVAR(sorted_doc,
"sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list");
static PyObject * static PyObject *
builtin_vars(PyObject *self, PyObject *args) builtin_vars(PyObject *self, PyObject *args)
@ -2055,6 +2099,7 @@ static PyMethodDef builtin_methods[] = {
{"repr", builtin_repr, METH_O, repr_doc}, {"repr", builtin_repr, METH_O, repr_doc},
{"round", builtin_round, METH_VARARGS, round_doc}, {"round", builtin_round, METH_VARARGS, round_doc},
{"setattr", builtin_setattr, METH_VARARGS, setattr_doc}, {"setattr", builtin_setattr, METH_VARARGS, setattr_doc},
{"sorted", (PyCFunction)builtin_sorted, METH_VARARGS | METH_KEYWORDS, sorted_doc},
{"sum", builtin_sum, METH_VARARGS, sum_doc}, {"sum", builtin_sum, METH_VARARGS, sum_doc},
#ifdef Py_USING_UNICODE #ifdef Py_USING_UNICODE
{"unichr", builtin_unichr, METH_VARARGS, unichr_doc}, {"unichr", builtin_unichr, METH_VARARGS, unichr_doc},