mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-38237: Make pow's arguments have more descriptive names and be keyword passable (GH-16302)
Edit: `math.pow` changes removed on Mark's request. https://bugs.python.org/issue38237 Automerge-Triggered-By: @rhettinger
This commit is contained in:
parent
e267793aa4
commit
87d6cd3604
6 changed files with 72 additions and 48 deletions
|
@ -779,26 +779,23 @@ A slash in the argument list of a function denotes that the parameters prior to
|
||||||
it are positional-only. Positional-only parameters are the ones without an
|
it are positional-only. Positional-only parameters are the ones without an
|
||||||
externally-usable name. Upon calling a function that accepts positional-only
|
externally-usable name. Upon calling a function that accepts positional-only
|
||||||
parameters, arguments are mapped to parameters based solely on their position.
|
parameters, arguments are mapped to parameters based solely on their position.
|
||||||
For example, :func:`pow` is a function that accepts positional-only parameters.
|
For example, :func:`divmod` is a function that accepts positional-only
|
||||||
Its documentation looks like this::
|
parameters. Its documentation looks like this::
|
||||||
|
|
||||||
>>> help(pow)
|
>>> help(divmod)
|
||||||
Help on built-in function pow in module builtins:
|
Help on built-in function divmod in module builtins:
|
||||||
|
|
||||||
pow(x, y, z=None, /)
|
divmod(x, y, /)
|
||||||
Equivalent to x**y (with two arguments) or x**y % z (with three arguments)
|
Return the tuple (x//y, x%y). Invariant: div*y + mod == x.
|
||||||
|
|
||||||
Some types, such as ints, are able to use a more efficient algorithm when
|
The slash at the end of the parameter list means that both parameters are
|
||||||
invoked using the three argument form.
|
positional-only. Thus, calling :func:`divmod` with keyword arguments would lead
|
||||||
|
to an error::
|
||||||
|
|
||||||
The slash at the end of the parameter list means that all three parameters are
|
>>> divmod(x=3, y=4)
|
||||||
positional-only. Thus, calling :func:`pow` with keyword arguments would lead to
|
|
||||||
an error::
|
|
||||||
|
|
||||||
>>> pow(x=3, y=4)
|
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
TypeError: pow() takes no keyword arguments
|
TypeError: divmod() takes no keyword arguments
|
||||||
|
|
||||||
|
|
||||||
Numbers and strings
|
Numbers and strings
|
||||||
|
|
|
@ -1274,11 +1274,12 @@ are always available. They are listed here in alphabetical order.
|
||||||
returns ``8364``. This is the inverse of :func:`chr`.
|
returns ``8364``. This is the inverse of :func:`chr`.
|
||||||
|
|
||||||
|
|
||||||
.. function:: pow(x, y[, z])
|
.. function:: pow(base, exp[, mod])
|
||||||
|
|
||||||
Return *x* to the power *y*; if *z* is present, return *x* to the power *y*,
|
Return *base* to the power *exp*; if *mod* is present, return *base* to the
|
||||||
modulo *z* (computed more efficiently than ``pow(x, y) % z``). The two-argument
|
power *exp*, modulo *mod* (computed more efficiently than
|
||||||
form ``pow(x, y)`` is equivalent to using the power operator: ``x**y``.
|
``pow(base, exp) % mod``). The two-argument form ``pow(base, exp)`` is
|
||||||
|
equivalent to using the power operator: ``base**exp``.
|
||||||
|
|
||||||
The arguments must have numeric types. With mixed operand types, the
|
The arguments must have numeric types. With mixed operand types, the
|
||||||
coercion rules for binary arithmetic operators apply. For :class:`int`
|
coercion rules for binary arithmetic operators apply. For :class:`int`
|
||||||
|
@ -1287,14 +1288,15 @@ are always available. They are listed here in alphabetical order.
|
||||||
converted to float and a float result is delivered. For example, ``10**2``
|
converted to float and a float result is delivered. For example, ``10**2``
|
||||||
returns ``100``, but ``10**-2`` returns ``0.01``.
|
returns ``100``, but ``10**-2`` returns ``0.01``.
|
||||||
|
|
||||||
For :class:`int` operands *x* and *y*, if *z* is present, *z* must also be
|
For :class:`int` operands *base* and *exp*, if *mod* is present, *mod* must
|
||||||
of integer type and *z* must be nonzero. If *z* is present and *y* is
|
also be of integer type and *mod* must be nonzero. If *mod* is present and
|
||||||
negative, *x* must be relatively prime to *z*. In that case, ``pow(inv_x,
|
*exp* is negative, *base* must be relatively prime to *mod*. In that case,
|
||||||
-y, z)`` is returned, where *inv_x* is an inverse to *x* modulo *z*.
|
``pow(inv_base, -exp, mod)`` is returned, where *inv_base* is an inverse to
|
||||||
|
*base* modulo *mod*.
|
||||||
|
|
||||||
Here's an example of computing an inverse for ``38`` modulo ``97``::
|
Here's an example of computing an inverse for ``38`` modulo ``97``::
|
||||||
|
|
||||||
>>> pow(38, -1, 97)
|
>>> pow(38, -1, mod=97)
|
||||||
23
|
23
|
||||||
>>> 23 * 38 % 97 == 1
|
>>> 23 * 38 % 97 == 1
|
||||||
True
|
True
|
||||||
|
@ -1304,6 +1306,10 @@ are always available. They are listed here in alphabetical order.
|
||||||
the second argument to be negative, permitting computation of modular
|
the second argument to be negative, permitting computation of modular
|
||||||
inverses.
|
inverses.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.9
|
||||||
|
Allow keyword arguments. Formerly, only positional arguments were
|
||||||
|
supported.
|
||||||
|
|
||||||
|
|
||||||
.. function:: print(*objects, sep=' ', end='\\n', file=sys.stdout, flush=False)
|
.. function:: print(*objects, sep=' ', end='\\n', file=sys.stdout, flush=False)
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import types
|
||||||
import unittest
|
import unittest
|
||||||
import warnings
|
import warnings
|
||||||
from contextlib import ExitStack
|
from contextlib import ExitStack
|
||||||
|
from functools import partial
|
||||||
from inspect import CO_COROUTINE
|
from inspect import CO_COROUTINE
|
||||||
from itertools import product
|
from itertools import product
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
|
@ -1206,6 +1207,18 @@ class BuiltinTest(unittest.TestCase):
|
||||||
|
|
||||||
self.assertRaises(TypeError, pow)
|
self.assertRaises(TypeError, pow)
|
||||||
|
|
||||||
|
# Test passing in arguments as keywords.
|
||||||
|
self.assertEqual(pow(0, exp=0), 1)
|
||||||
|
self.assertEqual(pow(base=2, exp=4), 16)
|
||||||
|
self.assertEqual(pow(base=5, exp=2, mod=14), 11)
|
||||||
|
twopow = partial(pow, base=2)
|
||||||
|
self.assertEqual(twopow(exp=5), 32)
|
||||||
|
fifth_power = partial(pow, exp=5)
|
||||||
|
self.assertEqual(fifth_power(2), 32)
|
||||||
|
mod10 = partial(pow, mod=10)
|
||||||
|
self.assertEqual(mod10(2, 6), 4)
|
||||||
|
self.assertEqual(mod10(exp=6, base=2), 4)
|
||||||
|
|
||||||
def test_input(self):
|
def test_input(self):
|
||||||
self.write_testfile()
|
self.write_testfile()
|
||||||
fp = open(TESTFN, 'r')
|
fp = open(TESTFN, 'r')
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
The arguments for the builtin pow function are more descriptive. They can now
|
||||||
|
also be passed in as keywords.
|
|
@ -1796,22 +1796,22 @@ builtin_ord(PyObject *module, PyObject *c)
|
||||||
/*[clinic input]
|
/*[clinic input]
|
||||||
pow as builtin_pow
|
pow as builtin_pow
|
||||||
|
|
||||||
x: object
|
base: object
|
||||||
y: object
|
exp: object
|
||||||
z: object = None
|
mod: object = None
|
||||||
/
|
|
||||||
|
|
||||||
Equivalent to x**y (with two arguments) or x**y % z (with three arguments)
|
Equivalent to base**exp (with two arguments) or base**exp % mod (with three arguments)
|
||||||
|
|
||||||
Some types, such as ints, are able to use a more efficient algorithm when
|
Some types, such as ints, are able to use a more efficient algorithm when
|
||||||
invoked using the three argument form.
|
invoked using the three argument form.
|
||||||
[clinic start generated code]*/
|
[clinic start generated code]*/
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_pow_impl(PyObject *module, PyObject *x, PyObject *y, PyObject *z)
|
builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp,
|
||||||
/*[clinic end generated code: output=50a14d5d130d404b input=653d57d38d41fc07]*/
|
PyObject *mod)
|
||||||
|
/*[clinic end generated code: output=3ca1538221bbf15f input=bd72d0a0ec8e5eb5]*/
|
||||||
{
|
{
|
||||||
return PyNumber_Power(x, y, z);
|
return PyNumber_Power(base, exp, mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
40
Python/clinic/bltinmodule.c.h
generated
40
Python/clinic/bltinmodule.c.h
generated
|
@ -608,39 +608,45 @@ PyDoc_STRVAR(builtin_ord__doc__,
|
||||||
{"ord", (PyCFunction)builtin_ord, METH_O, builtin_ord__doc__},
|
{"ord", (PyCFunction)builtin_ord, METH_O, builtin_ord__doc__},
|
||||||
|
|
||||||
PyDoc_STRVAR(builtin_pow__doc__,
|
PyDoc_STRVAR(builtin_pow__doc__,
|
||||||
"pow($module, x, y, z=None, /)\n"
|
"pow($module, /, base, exp, mod=None)\n"
|
||||||
"--\n"
|
"--\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Equivalent to x**y (with two arguments) or x**y % z (with three arguments)\n"
|
"Equivalent to base**exp (with two arguments) or base**exp % mod (with three arguments)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Some types, such as ints, are able to use a more efficient algorithm when\n"
|
"Some types, such as ints, are able to use a more efficient algorithm when\n"
|
||||||
"invoked using the three argument form.");
|
"invoked using the three argument form.");
|
||||||
|
|
||||||
#define BUILTIN_POW_METHODDEF \
|
#define BUILTIN_POW_METHODDEF \
|
||||||
{"pow", (PyCFunction)(void(*)(void))builtin_pow, METH_FASTCALL, builtin_pow__doc__},
|
{"pow", (PyCFunction)(void(*)(void))builtin_pow, METH_FASTCALL|METH_KEYWORDS, builtin_pow__doc__},
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_pow_impl(PyObject *module, PyObject *x, PyObject *y, PyObject *z);
|
builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp,
|
||||||
|
PyObject *mod);
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
builtin_pow(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
builtin_pow(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames)
|
||||||
{
|
{
|
||||||
PyObject *return_value = NULL;
|
PyObject *return_value = NULL;
|
||||||
PyObject *x;
|
static const char * const _keywords[] = {"base", "exp", "mod", NULL};
|
||||||
PyObject *y;
|
static _PyArg_Parser _parser = {NULL, _keywords, "pow", 0};
|
||||||
PyObject *z = Py_None;
|
PyObject *argsbuf[3];
|
||||||
|
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2;
|
||||||
|
PyObject *base;
|
||||||
|
PyObject *exp;
|
||||||
|
PyObject *mod = Py_None;
|
||||||
|
|
||||||
if (!_PyArg_CheckPositional("pow", nargs, 2, 3)) {
|
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 3, 0, argsbuf);
|
||||||
|
if (!args) {
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
x = args[0];
|
base = args[0];
|
||||||
y = args[1];
|
exp = args[1];
|
||||||
if (nargs < 3) {
|
if (!noptargs) {
|
||||||
goto skip_optional;
|
goto skip_optional_pos;
|
||||||
}
|
}
|
||||||
z = args[2];
|
mod = args[2];
|
||||||
skip_optional:
|
skip_optional_pos:
|
||||||
return_value = builtin_pow_impl(module, x, y, z);
|
return_value = builtin_pow_impl(module, base, exp, mod);
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
|
@ -849,4 +855,4 @@ builtin_issubclass(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
|
||||||
exit:
|
exit:
|
||||||
return return_value;
|
return return_value;
|
||||||
}
|
}
|
||||||
/*[clinic end generated code: output=4e118c2cd2cd98f3 input=a9049054013a1b77]*/
|
/*[clinic end generated code: output=1e2a6185e05ecd11 input=a9049054013a1b77]*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue