Skip to content

gh-130104: Call __rpow__ in ternary pow() if necessary #130251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 16, 2025

Conversation

serhiy-storchaka
Copy link
Member

@serhiy-storchaka serhiy-storchaka commented Feb 18, 2025

Previously it was only called in binary pow() and the binary power operator.


📚 Documentation preview 📚: https://cpython-previews--130251.org.readthedocs.build/

Previously it was only called in binary pow() and the binary
power operator.
@skirpichev skirpichev self-requested a review February 19, 2025 00:16
Copy link
Member

@skirpichev skirpichev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (few nitpicks)

Maybe it's possible to refactor code to avoid a copy of SLOT1BINFULL, but I doubt it worth efforts.

@@ -3356,10 +3356,15 @@ left undefined.
is called if ``type(x).__sub__(x, y)`` returns :data:`NotImplemented` or ``type(y)``
is a subclass of ``type(x)``. [#]_

.. index:: pair: built-in function; pow
Note that :meth:`__rpow__` should be defined to accept an optional third
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you should use object.__rpow__(self, other, modulo=None) signature?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand you. Were and how can it be used?

This sentence is a copy of the corresponding sentence for __pow__.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I meant L3329-3342 above.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. There are other similar cases (for example __round__), so I will left this for other issue. Actually, __pow__() and __round__() are never called with None, so it is not necessary that they support None.

@skirpichev
Copy link
Member

CC @picnixz (this is an alternative to #122193)

@picnixz picnixz self-requested a review March 2, 2025 13:14
Copy link
Member

@picnixz picnixz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First round of style review only. I'll look at the implementation and implications more in detail either later or tomorrow.

Comment on lines +335 to +339
* Three-argument :func:`pow` now try calling :meth:`~object.__rpow__` if necessary.
Previously it was only called in two-argument :func:`!pow` and the binary
power operator.
(Contributed by Serhiy Storchaka in :gh:`130104`.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Three-argument :func:`pow` now try calling :meth:`~object.__rpow__` if necessary.
Previously it was only called in two-argument :func:`!pow` and the binary
power operator.
(Contributed by Serhiy Storchaka in :gh:`130104`.)
* Three-argument :func:`pow` now try calling :meth:`~object.__rpow__` if necessary.
Previously it was only called in two-argument :func:`!pow` and the binary
power operator.
(Contributed by Serhiy Storchaka in :gh:`130104`.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference?

@@ -9813,13 +9813,46 @@ slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus)
{
if (modulus == Py_None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's insert some PEP-7 here if (modulus == Py_None) { ...

Comment on lines +9820 to +9822
int do_other = !Py_IS_TYPE(self, Py_TYPE(other)) &&
Py_TYPE(other)->tp_as_number != NULL &&
Py_TYPE(other)->tp_as_number->nb_power == slot_nb_power;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use a lot of Py_TYPE(other), so I think we can have a variable holding it just for readability.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is a copy of SLOT1BINFULL. I do not want to introduce more difference than necessary.

We can make SLOT1BINFULL supporting the third argument, but I am not sure that it is worth.

Comment on lines +9820 to +9822
int do_other = !Py_IS_TYPE(self, Py_TYPE(other)) &&
Py_TYPE(other)->tp_as_number != NULL &&
Py_TYPE(other)->tp_as_number->nb_power == slot_nb_power;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
int do_other = !Py_IS_TYPE(self, Py_TYPE(other)) &&
Py_TYPE(other)->tp_as_number != NULL &&
Py_TYPE(other)->tp_as_number->nb_power == slot_nb_power;
int do_other = !Py_IS_TYPE(self, Py_TYPE(other))
&& Py_TYPE(other)->tp_as_number != NULL
&& Py_TYPE(other)->tp_as_number->nb_power == slot_nb_power;

slot_nb_power, so check before calling self.__pow__. */

/* The following code is a copy of SLOT1BINFULL, but for three arguments. */
PyObject* stack[3];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
PyObject* stack[3];
PyObject *stack[3];

Comment on lines +9836 to +9837
if (r != Py_NotImplemented)
return r;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (r != Py_NotImplemented)
return r;
if (r != Py_NotImplemented) {
return r;
}

Comment on lines +9846 to +9848
if (r != Py_NotImplemented ||
Py_IS_TYPE(other, Py_TYPE(self)))
return r;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (r != Py_NotImplemented ||
Py_IS_TYPE(other, Py_TYPE(self)))
return r;
if (r != Py_NotImplemented || Py_IS_TYPE(other, Py_TYPE(self))) {
return r;
}

@picnixz
Copy link
Member

picnixz commented Mar 4, 2025

Sorry I didn't have time. I will leave for 10 days so I won't be able to review it. If you and Serhiy thinks it's good, then go ahead. If the PR is still not merged when I'm back then I'll try to review it.

As for whether I find it useful or not, my answer would be "yes".

@serhiy-storchaka serhiy-storchaka merged commit 62ff86f into python:main Apr 16, 2025
42 checks passed
@serhiy-storchaka serhiy-storchaka deleted the rpow branch April 16, 2025 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants