mirror of https://github.com/python/cpython
Issue 18111: Add a default argument to min() and max()
This commit is contained in:
parent
d7a034bd75
commit
4d6018fe45
|
@ -753,19 +753,22 @@ are always available. They are listed here in alphabetical order.
|
|||
already arranged into argument tuples, see :func:`itertools.starmap`\.
|
||||
|
||||
|
||||
.. function:: max(iterable, *[, key])
|
||||
.. function:: max(iterable, *[, default, key])
|
||||
max(arg1, arg2, *args[, key])
|
||||
|
||||
Return the largest item in an iterable or the largest of two or more
|
||||
arguments.
|
||||
|
||||
If one positional argument is provided, *iterable* must be a non-empty
|
||||
iterable (such as a non-empty string, tuple or list). The largest item
|
||||
in the iterable is returned. If two or more positional arguments are
|
||||
provided, the largest of the positional arguments is returned.
|
||||
If one positional argument is provided, it should be an :term:`iterable`.
|
||||
The largest item in the iterable is returned. If two or more positional
|
||||
arguments are provided, the smallest of the positional arguments is
|
||||
returned.
|
||||
|
||||
The optional keyword-only *key* argument specifies a one-argument ordering
|
||||
function like that used for :meth:`list.sort`.
|
||||
There are two optional keyword-only arguments. The *key* argument specifies
|
||||
a one-argument ordering function like that used for :meth:`list.sort`. The
|
||||
*default* argument specifies an object to return if the provided iterable is
|
||||
empty. If the iterable is empty and *default* is not provided, a
|
||||
:exc:`ValueError` is raised.
|
||||
|
||||
If multiple items are maximal, the function returns the first one
|
||||
encountered. This is consistent with other sort-stability preserving tools
|
||||
|
@ -781,19 +784,22 @@ are always available. They are listed here in alphabetical order.
|
|||
:ref:`typememoryview` for more information.
|
||||
|
||||
|
||||
.. function:: min(iterable, *[, key])
|
||||
.. function:: min(iterable, *[, default, key])
|
||||
min(arg1, arg2, *args[, key])
|
||||
|
||||
Return the smallest item in an iterable or the smallest of two or more
|
||||
arguments.
|
||||
|
||||
If one positional argument is provided, *iterable* must be a non-empty
|
||||
iterable (such as a non-empty string, tuple or list). The smallest item
|
||||
in the iterable is returned. If two or more positional arguments are
|
||||
provided, the smallest of the positional arguments is returned.
|
||||
If one positional argument is provided, it should be an :term:`iterable`.
|
||||
The smallest item in the iterable is returned. If two or more positional
|
||||
arguments are provided, the smallest of the positional arguments is
|
||||
returned.
|
||||
|
||||
The optional keyword-only *key* argument specifies a one-argument ordering
|
||||
function like that used for :meth:`list.sort`.
|
||||
There are two optional keyword-only arguments. The *key* argument specifies
|
||||
a one-argument ordering function like that used for :meth:`list.sort`. The
|
||||
*default* argument specifies an object to return if the provided iterable is
|
||||
empty. If the iterable is empty and *default* is not provided, a
|
||||
:exc:`ValueError` is raised.
|
||||
|
||||
If multiple items are minimal, the function returns the first one
|
||||
encountered. This is consistent with other sort-stability preserving tools
|
||||
|
|
|
@ -847,8 +847,19 @@ class BuiltinTest(unittest.TestCase):
|
|||
self.assertEqual(max(1, 2.0, 3), 3)
|
||||
self.assertEqual(max(1.0, 2, 3), 3)
|
||||
|
||||
self.assertRaises(TypeError, max)
|
||||
self.assertRaises(TypeError, max, 42)
|
||||
self.assertRaises(ValueError, max, ())
|
||||
class BadSeq:
|
||||
def __getitem__(self, index):
|
||||
raise ValueError
|
||||
self.assertRaises(ValueError, max, BadSeq())
|
||||
|
||||
for stmt in (
|
||||
"max(key=int)", # no args
|
||||
"max(default=None)",
|
||||
"max(1, 2, default=None)", # require container for default
|
||||
"max(default=None, key=int)",
|
||||
"max(1, key=int)", # single arg not iterable
|
||||
"max(1, 2, keystone=int)", # wrong keyword
|
||||
"max(1, 2, key=int, abc=int)", # two many keywords
|
||||
|
@ -865,6 +876,13 @@ class BuiltinTest(unittest.TestCase):
|
|||
self.assertEqual(max((1,2), key=neg), 1) # two elem iterable
|
||||
self.assertEqual(max(1, 2, key=neg), 1) # two elems
|
||||
|
||||
self.assertEqual(max((), default=None), None) # zero elem iterable
|
||||
self.assertEqual(max((1,), default=None), 1) # one elem iterable
|
||||
self.assertEqual(max((1,2), default=None), 2) # two elem iterable
|
||||
|
||||
self.assertEqual(max((), default=1, key=neg), 1)
|
||||
self.assertEqual(max((1, 2), default=3, key=neg), 1)
|
||||
|
||||
data = [random.randrange(200) for i in range(100)]
|
||||
keys = dict((elem, random.randrange(50)) for elem in data)
|
||||
f = keys.__getitem__
|
||||
|
@ -891,6 +909,9 @@ class BuiltinTest(unittest.TestCase):
|
|||
|
||||
for stmt in (
|
||||
"min(key=int)", # no args
|
||||
"min(default=None)",
|
||||
"min(1, 2, default=None)", # require container for default
|
||||
"min(default=None, key=int)",
|
||||
"min(1, key=int)", # single arg not iterable
|
||||
"min(1, 2, keystone=int)", # wrong keyword
|
||||
"min(1, 2, key=int, abc=int)", # two many keywords
|
||||
|
@ -907,6 +928,13 @@ class BuiltinTest(unittest.TestCase):
|
|||
self.assertEqual(min((1,2), key=neg), 2) # two elem iterable
|
||||
self.assertEqual(min(1, 2, key=neg), 2) # two elems
|
||||
|
||||
self.assertEqual(min((), default=None), None) # zero elem iterable
|
||||
self.assertEqual(min((1,), default=None), 1) # one elem iterable
|
||||
self.assertEqual(min((1,2), default=None), 1) # two elem iterable
|
||||
|
||||
self.assertEqual(min((), default=1, key=neg), 1)
|
||||
self.assertEqual(min((1, 2), default=1, key=neg), 2)
|
||||
|
||||
data = [random.randrange(200) for i in range(100)]
|
||||
keys = dict((elem, random.randrange(50)) for elem in data)
|
||||
f = keys.__getitem__
|
||||
|
|
|
@ -13,6 +13,10 @@ Core and Builtins
|
|||
- Issue #18184: PyUnicode_FromFormat() and PyUnicode_FromFormatV() now raise
|
||||
OverflowError when an argument of %c format is out of range.
|
||||
|
||||
- Issue #18111: The min() and max() functions now support a default argument
|
||||
to be returned instead of raising a ValueError on an empty sequence.
|
||||
(Contributed by Julian Berman.)
|
||||
|
||||
- Issue #18137: Detect integer overflow on precision in float.__format__()
|
||||
and complex.__format__().
|
||||
|
||||
|
|
|
@ -1329,26 +1329,35 @@ static PyObject *
|
|||
min_max(PyObject *args, PyObject *kwds, int op)
|
||||
{
|
||||
PyObject *v, *it, *item, *val, *maxitem, *maxval, *keyfunc=NULL;
|
||||
PyObject *emptytuple, *defaultval = NULL;
|
||||
static char *kwlist[] = {"key", "default", NULL};
|
||||
const char *name = op == Py_LT ? "min" : "max";
|
||||
const int positional = PyTuple_Size(args) > 1;
|
||||
int ret;
|
||||
|
||||
if (PyTuple_Size(args) > 1)
|
||||
if (positional)
|
||||
v = args;
|
||||
else if (!PyArg_UnpackTuple(args, (char *)name, 1, 1, &v))
|
||||
return NULL;
|
||||
|
||||
if (kwds != NULL && PyDict_Check(kwds) && PyDict_Size(kwds)) {
|
||||
keyfunc = PyDict_GetItemString(kwds, "key");
|
||||
if (PyDict_Size(kwds)!=1 || keyfunc == NULL) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%s() got an unexpected keyword argument", name);
|
||||
emptytuple = PyTuple_New(0);
|
||||
if (emptytuple == NULL)
|
||||
return NULL;
|
||||
ret = PyArg_ParseTupleAndKeywords(emptytuple, kwds, "|$OO", kwlist,
|
||||
&keyfunc, &defaultval);
|
||||
Py_DECREF(emptytuple);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
if (positional && defaultval != NULL) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"Cannot specify a default for %s() with multiple "
|
||||
"positional arguments", name);
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(keyfunc);
|
||||
}
|
||||
|
||||
it = PyObject_GetIter(v);
|
||||
if (it == NULL) {
|
||||
Py_XDECREF(keyfunc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1392,14 +1401,18 @@ min_max(PyObject *args, PyObject *kwds, int op)
|
|||
if (PyErr_Occurred())
|
||||
goto Fail_it;
|
||||
if (maxval == NULL) {
|
||||
assert(maxitem == NULL);
|
||||
if (defaultval != NULL) {
|
||||
Py_INCREF(defaultval);
|
||||
maxitem = defaultval;
|
||||
} else {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%s() arg is an empty sequence", name);
|
||||
assert(maxitem == NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
Py_DECREF(maxval);
|
||||
Py_DECREF(it);
|
||||
Py_XDECREF(keyfunc);
|
||||
return maxitem;
|
||||
|
||||
Fail_it_item_and_val:
|
||||
|
@ -1410,7 +1423,6 @@ Fail_it:
|
|||
Py_XDECREF(maxval);
|
||||
Py_XDECREF(maxitem);
|
||||
Py_DECREF(it);
|
||||
Py_XDECREF(keyfunc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue