Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
70b64fce
Commit
70b64fce
authored
Jan 30, 2008
by
Raymond Hettinger
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #1771: Remove cmp parameter from list.sort() and builtin.sorted().
parent
4f066126
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
82 additions
and
265 deletions
+82
-265
Doc/library/functions.rst
Doc/library/functions.rst
+2
-13
Doc/library/stdtypes.rst
Doc/library/stdtypes.rst
+1
-13
Lib/cookielib.py
Lib/cookielib.py
+1
-2
Lib/pstats.py
Lib/pstats.py
+11
-1
Lib/test/list_tests.py
Lib/test/list_tests.py
+12
-5
Lib/test/test_builtin.py
Lib/test/test_builtin.py
+0
-3
Lib/test/test_sort.py
Lib/test/test_sort.py
+18
-32
Misc/NEWS
Misc/NEWS
+2
-0
Objects/listobject.c
Objects/listobject.c
+29
-190
Python/bltinmodule.c
Python/bltinmodule.c
+6
-6
No files found.
Doc/library/functions.rst
View file @
70b64fce
...
...
@@ -959,31 +959,20 @@ available. They are listed here in alphabetical order.
``a[start:stop:step]`` or ``a[start:stop, i]``.
.. function:: sorted(iterable[,
cmp[, key[, reverse]
]])
.. function:: sorted(iterable[,
key[, reverse
]])
Return a new sorted list from the items in *iterable*.
The optional arguments *
cmp*, *key*,
and *reverse* have the same meaning as
The optional arguments *
key*
and *reverse* have the same meaning as
those for the :meth:`list.sort` method (described in section
:ref:`typesseq-mutable`).
*cmp* specifies a custom comparison function of two arguments (iterable
elements) which should return a negative, zero or positive number depending on
whether the first argument is considered smaller than, equal to, or larger than
the second argument: ``cmp=lambda x,y: cmp(x.lower(), y.lower())``. The default
value is ``None``.
*key* specifies a function of one argument that is used to extract a comparison
key from each list element: ``key=str.lower``. The default value is ``None``.
*reverse* is a boolean value. If set to ``True``, then the list elements are
sorted as if each comparison were reversed.
In general, the *key* and *reverse* conversion processes are much faster than
specifying an equivalent *cmp* function. This is because *cmp* is called
multiple times for each list element while *key* and *reverse* touch each
element only once.
.. function:: staticmethod(function)
...
...
Doc/library/stdtypes.rst
View file @
70b64fce
...
...
@@ -1266,8 +1266,7 @@ Note that while lists allow their items to be of any type, bytearray object
| ``s.reverse()`` | reverses the items of *s* in | \(6) |
| | place | |
+------------------------------+--------------------------------+---------------------+
| ``s.sort([cmp[, key[, | sort the items of *s* in place | (6), (7) |
| reverse]]])`` | | |
| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7) |
+------------------------------+--------------------------------+---------------------+
.. index::
...
...
@@ -1321,23 +1320,12 @@ Notes:
The :meth:`sort` method takes optional arguments for controlling the
comparisons.
*cmp* specifies a custom comparison function of two arguments (list items) which
should return a negative, zero or positive number depending on whether the first
argument is considered smaller than, equal to, or larger than the second
argument: ``cmp=lambda x,y: cmp(x.lower(), y.lower())``. The default value
is ``None``.
*key* specifies a function of one argument that is used to extract a comparison
key from each list element: ``key=str.lower``. The default value is ``None``.
*reverse* is a boolean value. If set to ``True``, then the list elements are
sorted as if each comparison were reversed.
In general, the *key* and *reverse* conversion processes are much faster than
specifying an equivalent *cmp* function. This is because *cmp* is called
multiple times for each list element while *key* and *reverse* touch each
element only once.
Starting with Python 2.3, the :meth:`sort` method is guaranteed to be stable. A
sort is stable if it guarantees not to change the relative order of elements
that compare equal --- this is helpful for sorting in multiple passes (for
...
...
Lib/cookielib.py
View file @
70b64fce
...
...
@@ -1255,8 +1255,7 @@ class CookieJar:
"""
# add cookies in order of most specific (ie. longest) path first
def decreasing_size(a, b): return cmp(len(b.path), len(a.path))
cookies.sort(decreasing_size)
cookies.sort(key=lambda a: len(a.path), reverse=True)
version_set = False
...
...
Lib/pstats.py
View file @
70b64fce
...
...
@@ -238,7 +238,7 @@ class Stats:
stats_list
.
append
((
cc
,
nc
,
tt
,
ct
)
+
func
+
(
func_std_string
(
func
),
func
))
stats_list
.
sort
(
TupleComp
(
sort_tuple
).
compare
)
stats_list
.
sort
(
key
=
CmpToKey
(
TupleComp
(
sort_tuple
).
compare
)
)
self
.
fcn_list
=
fcn_list
=
[]
for
tuple
in
stats_list
:
...
...
@@ -470,6 +470,16 @@ class TupleComp:
return
direction
return
0
def
CmpToKey
(
mycmp
):
'Convert a cmp= function into a key= function'
class
K
(
object
):
def
__init__
(
self
,
obj
):
self
.
obj
=
obj
def
__lt__
(
self
,
other
):
return
mycmp
(
self
.
obj
,
other
.
obj
)
==
-
1
return
K
#**************************************************************************
# func_name is a triple (file:string, line:int, name:string)
...
...
Lib/test/list_tests.py
View file @
70b64fce
...
...
@@ -8,6 +8,15 @@ import os
import
unittest
from
test
import
test_support
,
seq_tests
def
CmpToKey
(
mycmp
):
'Convert a cmp= function into a key= function'
class
K
(
object
):
def
__init__
(
self
,
obj
):
self
.
obj
=
obj
def
__lt__
(
self
,
other
):
return
mycmp
(
self
.
obj
,
other
.
obj
)
==
-
1
return
K
class
CommonTest
(
seq_tests
.
CommonTest
):
def
test_init
(
self
):
...
...
@@ -430,23 +439,21 @@ class CommonTest(seq_tests.CommonTest):
def
revcmp
(
a
,
b
):
return
cmp
(
b
,
a
)
u
.
sort
(
revcmp
)
u
.
sort
(
key
=
CmpToKey
(
revcmp
)
)
self
.
assertEqual
(
u
,
self
.
type2test
([
2
,
1
,
0
,
-
1
,
-
2
]))
# The following dumps core in unpatched Python 1.5:
def
myComparison
(
x
,
y
):
return
cmp
(
x
%
3
,
y
%
7
)
z
=
self
.
type2test
(
range
(
12
))
z
.
sort
(
myComparison
)
z
.
sort
(
key
=
CmpToKey
(
myComparison
)
)
self
.
assertRaises
(
TypeError
,
z
.
sort
,
2
)
def
selfmodifyingComparison
(
x
,
y
):
z
.
append
(
1
)
return
cmp
(
x
,
y
)
self
.
assertRaises
(
ValueError
,
z
.
sort
,
selfmodifyingComparison
)
self
.
assertRaises
(
TypeError
,
z
.
sort
,
lambda
x
,
y
:
's'
)
self
.
assertRaises
(
ValueError
,
z
.
sort
,
key
=
CmpToKey
(
selfmodifyingComparison
))
self
.
assertRaises
(
TypeError
,
z
.
sort
,
42
,
42
,
42
,
42
)
...
...
Lib/test/test_builtin.py
View file @
70b64fce
...
...
@@ -1764,9 +1764,6 @@ class TestSorted(unittest.TestCase):
data
.
reverse
()
random
.
shuffle
(
copy
)
self
.
assertEqual
(
data
,
sorted
(
copy
,
cmp
=
lambda
x
,
y
:
(
x
<
y
)
-
(
x
>
y
)))
self
.
assertNotEqual
(
data
,
copy
)
random
.
shuffle
(
copy
)
self
.
assertEqual
(
data
,
sorted
(
copy
,
key
=
lambda
x
:
-
x
))
self
.
assertNotEqual
(
data
,
copy
)
random
.
shuffle
(
copy
)
...
...
Lib/test/test_sort.py
View file @
70b64fce
...
...
@@ -6,6 +6,15 @@ import unittest
verbose
=
test_support
.
verbose
nerrors
=
0
def
CmpToKey
(
mycmp
):
'Convert a cmp= function into a key= function'
class
K
(
object
):
def
__init__
(
self
,
obj
):
self
.
obj
=
obj
def
__lt__
(
self
,
other
):
return
mycmp
(
self
.
obj
,
other
.
obj
)
==
-
1
return
K
def
check
(
tag
,
expected
,
raw
,
compare
=
None
):
global
nerrors
...
...
@@ -14,7 +23,7 @@ def check(tag, expected, raw, compare=None):
orig
=
raw
[:]
# save input in case of error
if
compare
:
raw
.
sort
(
compare
)
raw
.
sort
(
key
=
CmpToKey
(
compare
)
)
else
:
raw
.
sort
()
...
...
@@ -99,7 +108,7 @@ class TestBase(unittest.TestCase):
print
(
" Checking against an insane comparison function."
)
print
(
" If the implementation isn't careful, this may segfault."
)
s
=
x
[:]
s
.
sort
(
lambda
a
,
b
:
int
(
random
.
random
()
*
3
)
-
1
)
s
.
sort
(
key
=
CmpToKey
(
lambda
a
,
b
:
int
(
random
.
random
()
*
3
)
-
1
)
)
check
(
"an insane function left some permutation"
,
x
,
s
)
x
=
[
Complains
(
i
)
for
i
in
x
]
...
...
@@ -141,14 +150,6 @@ class TestBugs(unittest.TestCase):
L
=
[
C
()
for
i
in
range
(
50
)]
self
.
assertRaises
(
ValueError
,
L
.
sort
)
def
test_cmpNone
(
self
):
# Testing None as a comparison function.
L
=
list
(
range
(
50
))
random
.
shuffle
(
L
)
L
.
sort
(
None
)
self
.
assertEqual
(
L
,
list
(
range
(
50
)))
def
test_undetected_mutation
(
self
):
# Python 2.4a1 did not always detect mutation
memorywaster
=
[]
...
...
@@ -158,12 +159,12 @@ class TestBugs(unittest.TestCase):
L
.
pop
()
return
cmp
(
x
,
y
)
L
=
[
1
,
2
]
self
.
assertRaises
(
ValueError
,
L
.
sort
,
mutating_cmp
)
self
.
assertRaises
(
ValueError
,
L
.
sort
,
key
=
CmpToKey
(
mutating_cmp
)
)
def
mutating_cmp
(
x
,
y
):
L
.
append
(
3
)
del
L
[:]
return
cmp
(
x
,
y
)
self
.
assertRaises
(
ValueError
,
L
.
sort
,
mutating_cmp
)
self
.
assertRaises
(
ValueError
,
L
.
sort
,
key
=
CmpToKey
(
mutating_cmp
)
)
memorywaster
=
[
memorywaster
]
#==============================================================================
...
...
@@ -175,11 +176,11 @@ class TestDecorateSortUndecorate(unittest.TestCase):
copy
=
data
[:]
random
.
shuffle
(
data
)
data
.
sort
(
key
=
str
.
lower
)
copy
.
sort
(
cmp
=
lambda
x
,
y
:
cmp
(
x
.
lower
(),
y
.
lower
(
)))
copy
.
sort
(
key
=
CmpToKey
(
lambda
x
,
y
:
cmp
(
x
.
lower
(),
y
.
lower
()
)))
def
test_baddecorator
(
self
):
data
=
'The quick Brown fox Jumped over The lazy Dog'
.
split
()
self
.
assertRaises
(
TypeError
,
data
.
sort
,
None
,
lambda
x
,
y
:
0
)
self
.
assertRaises
(
TypeError
,
data
.
sort
,
key
=
lambda
x
,
y
:
0
)
def
test_stability
(
self
):
data
=
[(
random
.
randrange
(
100
),
i
)
for
i
in
range
(
200
)]
...
...
@@ -188,25 +189,11 @@ class TestDecorateSortUndecorate(unittest.TestCase):
copy
.
sort
()
# sort using both fields
self
.
assertEqual
(
data
,
copy
)
# should get the same result
def
test_cmp_and_key_combination
(
self
):
# Verify that the wrapper has been removed
def
compare
(
x
,
y
):
self
.
assertEqual
(
type
(
x
),
str
)
self
.
assertEqual
(
type
(
x
),
str
)
return
cmp
(
x
,
y
)
data
=
'The quick Brown fox Jumped over The lazy Dog'
.
split
()
data
.
sort
(
cmp
=
compare
,
key
=
str
.
lower
)
def
test_badcmp_with_key
(
self
):
# Verify that the wrapper has been removed
data
=
'The quick Brown fox Jumped over The lazy Dog'
.
split
()
self
.
assertRaises
(
TypeError
,
data
.
sort
,
"bad"
,
str
.
lower
)
def
test_key_with_exception
(
self
):
# Verify that the wrapper has been removed
data
=
list
(
range
(
-
2
,
2
))
dup
=
data
[:]
self
.
assertRaises
(
ZeroDivisionError
,
data
.
sort
,
None
,
lambda
x
:
1
/
x
)
self
.
assertRaises
(
ZeroDivisionError
,
data
.
sort
,
key
=
lambda
x
:
1
/
x
)
self
.
assertEqual
(
data
,
dup
)
def
test_key_with_mutation
(
self
):
...
...
@@ -254,14 +241,13 @@ class TestDecorateSortUndecorate(unittest.TestCase):
random
.
shuffle
(
data
)
data
.
sort
(
reverse
=
True
)
self
.
assertEqual
(
data
,
list
(
range
(
99
,
-
1
,
-
1
)))
self
.
assertRaises
(
TypeError
,
data
.
sort
,
"wrong type"
)
def
test_reverse_stability
(
self
):
data
=
[(
random
.
randrange
(
100
),
i
)
for
i
in
range
(
200
)]
copy1
=
data
[:]
copy2
=
data
[:]
data
.
sort
(
cmp
=
lambda
x
,
y
:
cmp
(
x
[
0
],
y
[
0
]
),
reverse
=
True
)
copy1
.
sort
(
cmp
=
lambda
x
,
y
:
cmp
(
y
[
0
],
x
[
0
]
))
data
.
sort
(
key
=
CmpToKey
(
lambda
x
,
y
:
cmp
(
x
[
0
],
y
[
0
])
),
reverse
=
True
)
copy1
.
sort
(
key
=
CmpToKey
(
lambda
x
,
y
:
cmp
(
y
[
0
],
x
[
0
])
))
self
.
assertEqual
(
data
,
copy1
)
copy2
.
sort
(
key
=
lambda
x
:
x
[
0
],
reverse
=
True
)
self
.
assertEqual
(
data
,
copy2
)
...
...
Misc/NEWS
View file @
70b64fce
...
...
@@ -14,6 +14,8 @@ Core and Builtins
- Issue #1973: bytes.fromhex('') raises SystemError
- Issue #1771: remove cmp parameter from sorted() and list.sort()
- Issue #1969: split and rsplit in bytearray are inconsistent
- map() and itertools.imap() no longer accept None for the first argument.
...
...
Objects/listobject.c
View file @
70b64fce
This diff is collapsed.
Click to expand it.
Python/bltinmodule.c
View file @
70b64fce
...
...
@@ -1494,14 +1494,14 @@ Precision may be negative.");
static
PyObject
*
builtin_sorted
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
PyObject
*
newlist
,
*
v
,
*
seq
,
*
compare
=
NULL
,
*
keyfunc
=
NULL
,
*
newargs
;
PyObject
*
newlist
,
*
v
,
*
seq
,
*
keyfunc
=
NULL
,
*
newargs
;
PyObject
*
callable
;
static
char
*
kwlist
[]
=
{
"iterable"
,
"
cmp"
,
"
key"
,
"reverse"
,
0
};
static
char
*
kwlist
[]
=
{
"iterable"
,
"key"
,
"reverse"
,
0
};
int
reverse
;
/* args 1-
4
should match listsort in Objects/listobject.c */
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|O
O
i:sorted"
,
kwlist
,
&
seq
,
&
compare
,
&
keyfunc
,
&
reverse
))
/* args 1-
3
should match listsort in Objects/listobject.c */
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O|Oi:sorted"
,
kwlist
,
&
seq
,
&
keyfunc
,
&
reverse
))
return
NULL
;
newlist
=
PySequence_List
(
seq
);
...
...
@@ -1533,7 +1533,7 @@ builtin_sorted(PyObject *self, PyObject *args, PyObject *kwds)
}
PyDoc_STRVAR
(
sorted_doc
,
"sorted(iterable,
cmp=None,
key=None, reverse=False) --> new sorted list"
);
"sorted(iterable, key=None, reverse=False) --> new sorted list"
);
static
PyObject
*
builtin_vars
(
PyObject
*
self
,
PyObject
*
args
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment