classification
Title: Expose meaningful keyword arguments for pow()
Type: enhancement Stage: resolved
Components: Library (Lib) Versions: Python 3.9, Python 3.8
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: ammar2, lukasz.langa, mark.dickinson, miss-islington, rhettinger, serhiy.storchaka
Priority: normal Keywords: easy (C), patch

Created on 2019-09-20 17:21 by rhettinger, last changed 2019-09-21 20:44 by serhiy.storchaka. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 16302 merged ammar2, 2019-09-20 18:28
PR 16320 merged miss-islington, 2019-09-21 07:59
PR 16323 merged miss-islington, 2019-09-21 20:32
Messages (19)
msg352876 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-09-20 17:21
Current signature:

    pow(x, y, z=None, /)


Proposed signature:

    pow(base, exp, mod=None)


Benefits:

* Meaningful and self-explanatory parameters in tooltips

* Optionally clearer calls for the three argument form:

     pow(2, 5, mod=4)

* More usable with partial():

     squared = partial(pow, exp=2)
msg352877 - (view) Author: Ammar Askar (ammar2) * (Python triager) Date: 2019-09-20 17:28
Looks like a solid proposal, I especially like the clarity for the 3-argument call. Often beginners ask about why there's a third argument in pow especially when teaching RSA and number-theoretic stuff.

Do you mind if I take this on Raymond?
msg352878 - (view) Author: Ammar Askar (ammar2) * (Python triager) Date: 2019-09-20 17:59
Actually quick question, should a similar change be made for `math.pow` for consistency's sake?
msg352879 - (view) Author: Ammar Askar (ammar2) * (Python triager) Date: 2019-09-20 18:29
I've made a PR, feel free to close it if you'd rather implement this yourself or this proposal won't be accepted :)
msg352880 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-20 18:37
You can use a lambda instead of partial:

    squared = lambda x: pow(x, 2)

Proposed names look meaningful. But after adding support of keyword arguments please compare performance of the old and the new functions. I expect that the difference will be small, but we need to check.
msg352881 - (view) Author: Ammar Askar (ammar2) * (Python triager) Date: 2019-09-20 19:02
Here's a little microbenchmark, let me know if there's anything specific you'd like to see:

Before
======

> python -m pyperf timeit "from test.test_builtin import BuiltinTest; tst = BuiltinTest()" -- "tst.test_pow()"

Mean +- std dev: 3.80 us +- 0.23 us

> python -m pyperf timeit "pow(23, 19, 3)"

Mean +- std dev: 519 ns +- 12 ns


After
=====

> python -m pyperf timeit "from test.test_builtin import BuiltinTest; tst = BuiltinTest()" -- "tst.test_pow()"

Mean +- std dev: 3.80 us +- 0.26 us

> python -m pyperf timeit "pow(23, 19, 3)"

Mean +- std dev: 526 ns +- 18 ns
msg352885 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2019-09-20 20:16
The proposal sounds reasonable to me.

> should a similar change be made for `math.pow` for consistency's sake?

I'd leave math.pow alone here.
msg352886 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-20 20:17
Thank you. Could you please test simpler examples like pow(2, 3)? Please use the --duplicate option.
msg352887 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-20 20:18
And pow(2.0, 3.0) please.
msg352895 - (view) Author: Ammar Askar (ammar2) * (Python triager) Date: 2019-09-20 21:29
Before
======

>python -m pyperf timeit "pow(2, 3)" --duplicate 100000
Mean +- std dev: 242 ns +- 19 ns

> python -m pyperf timeit "pow(2.0, 3.0)" --duplicate 100000
Mean +- std dev: 197 ns +- 16 ns

After
=====

> python -m pyperf timeit "pow(2, 3)" --duplicate 100000
Mean +- std dev: 243 ns +- 11 ns

> python -m pyperf timeit "pow(2.0, 3.0)" --duplicate 100000
Mean +- std dev: 200 ns +- 14 ns
msg352900 - (view) Author: Ammar Askar (ammar2) * (Python triager) Date: 2019-09-20 21:52
math.pow changes removed from PR
msg352923 - (view) Author: miss-islington (miss-islington) Date: 2019-09-21 04:28
New changeset 87d6cd3604e5c83c06339276228139f5e040b0e7 by Miss Islington (bot) (Ammar Askar) in branch 'master':
bpo-38237: Make pow's arguments have more descriptive names and be keyword passable (GH-16302)
https://github.com/python/cpython/commit/87d6cd3604e5c83c06339276228139f5e040b0e7
msg352924 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-09-21 04:29
Thanks Ammar
msg352927 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-21 05:54
Thank you for your contribution Ammar! Nice work!
msg352933 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-09-21 08:22
New changeset 37bc93552375cb1bc616927b5c1905bae3c0e99d by Raymond Hettinger (Miss Islington (bot)) in branch '3.8':
bpo-38237: Let pow() support keyword arguments (GH-16302) (GH-16320)
https://github.com/python/cpython/commit/37bc93552375cb1bc616927b5c1905bae3c0e99d
msg352939 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-21 10:11
Isn't it a new feature? Isn't it too later to add it to 3.8?
msg352944 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-09-21 16:50
As noted in the checkin, this was backported with the release manager's assent.

FWIW, pow() itself is an old feature, recently enhanced to support negative powers in a given modulus.  When the enhancement went in, we should have done this as well.
msg352951 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2019-09-21 20:32
New changeset 24231ca75c721c8167a7394deb300727ccdcba51 by Raymond Hettinger (Miss Islington (bot)) in branch '3.8':
bpo-38237: Shorter docstring (GH-16322) (GH-16323)
https://github.com/python/cpython/commit/24231ca75c721c8167a7394deb300727ccdcba51
msg352952 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2019-09-21 20:44
Thank you for the explanation Raymond and sorry for the disturb. My mistake, I had not noticed the release manager's assent.
History
Date User Action Args
2019-09-21 20:44:01serhiy.storchakasetmessages: + msg352952
2019-09-21 20:32:32miss-islingtonsetpull_requests: + pull_request15901
2019-09-21 20:32:11rhettingersetmessages: + msg352951
2019-09-21 16:50:01rhettingersetstatus: open -> closed

messages: + msg352944
versions: + Python 3.8
2019-09-21 10:11:28serhiy.storchakasetstatus: closed -> open
nosy: + lukasz.langa
messages: + msg352939

2019-09-21 08:22:37rhettingersetmessages: + msg352933
2019-09-21 07:59:56miss-islingtonsetpull_requests: + pull_request15897
2019-09-21 05:54:52serhiy.storchakasetmessages: + msg352927
2019-09-21 04:29:31rhettingersetstatus: open -> closed
resolution: fixed
messages: + msg352924

stage: patch review -> resolved
2019-09-21 04:28:53miss-islingtonsetnosy: + miss-islington
messages: + msg352923
2019-09-21 01:18:18rhettingersetassignee: rhettinger
2019-09-20 21:52:49ammar2setmessages: + msg352900
2019-09-20 21:29:54ammar2setmessages: + msg352895
2019-09-20 20:18:57serhiy.storchakasetmessages: + msg352887
2019-09-20 20:17:23serhiy.storchakasetmessages: + msg352886
2019-09-20 20:16:14mark.dickinsonsetmessages: + msg352885
2019-09-20 19:02:06ammar2setmessages: + msg352881
2019-09-20 18:37:05serhiy.storchakasetnosy: + serhiy.storchaka
messages: + msg352880
2019-09-20 18:29:35ammar2setmessages: + msg352879
2019-09-20 18:28:49ammar2setkeywords: + patch
stage: patch review
pull_requests: + pull_request15887
2019-09-20 17:59:02ammar2setmessages: + msg352878
2019-09-20 17:28:14ammar2setnosy: + ammar2
messages: + msg352877
2019-09-20 17:21:42rhettingercreate