mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +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 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 @@ def test_pow(self): | ||||||
| 
 | 
 | ||||||
|         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
	
	 Ammar Askar
						Ammar Askar