Browse Source

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
pull/16322/head
Ammar Askar 6 years ago
committed by Miss Islington (bot)
parent
commit
87d6cd3604
  1. 25
      Doc/faq/programming.rst
  2. 24
      Doc/library/functions.rst
  3. 13
      Lib/test/test_builtin.py
  4. 2
      Misc/NEWS.d/next/Library/2019-09-20-14-27-17.bpo-38237.xRUZbx.rst
  5. 16
      Python/bltinmodule.c
  6. 42
      Python/clinic/bltinmodule.c.h

25
Doc/faq/programming.rst

@ -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.
Its documentation looks like this::
For example, :func:`divmod` is a function that accepts positional-only
parameters. Its documentation looks like this::
>>> help(pow)
Help on built-in function pow in module builtins:
>>> help(divmod)
Help on built-in function divmod in module builtins:
pow(x, y, z=None, /)
Equivalent to x**y (with two arguments) or x**y % z (with three arguments)
divmod(x, y, /)
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
invoked using the three argument form.
The slash at the end of the parameter list means that both parameters are
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
positional-only. Thus, calling :func:`pow` with keyword arguments would lead to
an error::
>>> pow(x=3, y=4)
>>> divmod(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

24
Doc/library/functions.rst

@ -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*,
modulo *z* (computed more efficiently than ``pow(x, y) % z``). The two-argument
form ``pow(x, y)`` is equivalent to using the power operator: ``x**y``.
Return *base* to the power *exp*; if *mod* is present, return *base* to the
power *exp*, modulo *mod* (computed more efficiently than
``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
of integer type and *z* must be nonzero. If *z* is present and *y* is
negative, *x* must be relatively prime to *z*. In that case, ``pow(inv_x,
-y, z)`` is returned, where *inv_x* is an inverse to *x* modulo *z*.
For :class:`int` operands *base* and *exp*, if *mod* is present, *mod* must
also be of integer type and *mod* must be nonzero. If *mod* is present and
*exp* is negative, *base* must be relatively prime to *mod*. In that case,
``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)

13
Lib/test/test_builtin.py

@ -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')

2
Misc/NEWS.d/next/Library/2019-09-20-14-27-17.bpo-38237.xRUZbx.rst

@ -0,0 +1,2 @@
The arguments for the builtin pow function are more descriptive. They can now
also be passed in as keywords.

16
Python/bltinmodule.c

@ -1796,22 +1796,22 @@ builtin_ord(PyObject *module, PyObject *c)
/*[clinic input] /*[clinic input]
pow as builtin_pow pow as builtin_pow
x: object
y: object
z: object = None
/
base: object
exp: object
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)
/*[clinic end generated code: output=50a14d5d130d404b input=653d57d38d41fc07]*/
builtin_pow_impl(PyObject *module, PyObject *base, PyObject *exp,
PyObject *mod)
/*[clinic end generated code: output=3ca1538221bbf15f input=bd72d0a0ec8e5eb5]*/
{ {
return PyNumber_Power(x, y, z);
return PyNumber_Power(base, exp, mod);
} }

42
Python/clinic/bltinmodule.c.h

@ -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;
PyObject *y;
PyObject *z = Py_None;
if (!_PyArg_CheckPositional("pow", nargs, 2, 3)) {
static const char * const _keywords[] = {"base", "exp", "mod", NULL};
static _PyArg_Parser _parser = {NULL, _keywords, "pow", 0};
PyObject *argsbuf[3];
Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 2;
PyObject *base;
PyObject *exp;
PyObject *mod = Py_None;
args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 2, 3, 0, argsbuf);
if (!args) {
goto exit; goto exit;
} }
x = args[0];
y = args[1];
if (nargs < 3) {
goto skip_optional;
base = args[0];
exp = args[1];
if (!noptargs) {
goto skip_optional_pos;
} }
z = args[2];
skip_optional:
return_value = builtin_pow_impl(module, x, y, z);
mod = args[2];
skip_optional_pos:
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…
Cancel
Save