Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Python: Python

in-place exponentiation incongruities

 

 

Python python RSS feed   Index | Next | Previous | View Threaded


giacomo.alzetta at gmail

Aug 11, 2012, 9:54 AM

Post #1 of 8 (911 views)
Permalink
in-place exponentiation incongruities

I've noticed some incongruities regarding in-place exponentiation.

On the C side nb_inplace_power is a ternary function, like nb_power (see here: http://docs.python.org/c-api/typeobj.html?highlight=numbermethods#PyNumberMethods).

Obviously you can't pass the third argument using the usual in-place syntax "**=".
Nevertheless I'd expect to be able to provide the third argument using operator.ipow. But the operator module accept only the two parameter variant.

The Number Protocol specify that the ipow operation ""is the equivalent of the Python statement o1 **= o2 when o3 is Py_None, or an in-place variant of pow(o1, o2, o3) otherwise.""

Since "operator" claims to be contain a "function port" of the operators, I'd expect it to implement ipow with three arguments.
I don't see any problem in adding the third argument to it(I mean, sure right now any code that calls ipow(a,b,c) [if exists] is broken, because it will just raise a TypeError, thus adding the argument will not break any code, and would provide more functionality.

Also, I don't think there are many objects in the build-ins or standardlib which implement an in-place exponentiation, so this means there wont be much code to change.

So my question is: why are there this incongruities?
Is there any chance to see this fixed? (in the operator module, or changing the documentation)

By the way: I'm asking this because I'm implementing a C-extension and I'd like to implement both pow and ipow. And since it's about polynomials on (Z/nZ)[x]/x^r-1, using the third argument always makes sense.
--
http://mail.python.org/mailman/listinfo/python-list


steve+comp.lang.python at pearwood

Aug 11, 2012, 9:28 PM

Post #2 of 8 (885 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

On Sat, 11 Aug 2012 09:54:56 -0700, Giacomo Alzetta wrote:

> I've noticed some incongruities regarding in-place exponentiation.
>
> On the C side nb_inplace_power is a ternary function, like nb_power (see
> here:
> http://docs.python.org/c-api/typeobj.html?
highlight=numbermethods#PyNumberMethods).
>
> Obviously you can't pass the third argument using the usual in-place
> syntax "**=". Nevertheless I'd expect to be able to provide the third
> argument using operator.ipow. But the operator module accept only the
> two parameter variant.

Why? The operator module implements the ** operator, not the pow()
function. If you want the pow() function, you can just use it directly,
no need to use operator.pow or operator.ipow.

Since ** is a binary operator, it can only accept two arguments.


> The Number Protocol specify that the ipow operation ""is the equivalent
> of the Python statement o1 **= o2 when o3 is Py_None, or an in-place
> variant of pow(o1, o2, o3) otherwise.""

Where is that from?


--
Steven
--
http://mail.python.org/mailman/listinfo/python-list


giacomo.alzetta at gmail

Aug 12, 2012, 12:14 AM

Post #3 of 8 (884 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

Il giorno domenica 12 agosto 2012 06:28:10 UTC+2, Steven D'Aprano ha scritto:
> On Sat, 11 Aug 2012 09:54:56 -0700, Giacomo Alzetta wrote:
>
>
>
> > I've noticed some incongruities regarding in-place exponentiation.
>
> >
>
> > On the C side nb_inplace_power is a ternary function, like nb_power (see
>
> > here:
>
> > http://docs.python.org/c-api/typeobj.html?
>
> highlight=numbermethods#PyNumberMethods).
>
> >
>
> > Obviously you can't pass the third argument using the usual in-place
>
> > syntax "**=". Nevertheless I'd expect to be able to provide the third
>
> > argument using operator.ipow. But the operator module accept only the
>
> > two parameter variant.
>
>
>
> Why? The operator module implements the ** operator, not the pow()
>
> function. If you want the pow() function, you can just use it directly,
>
> no need to use operator.pow or operator.ipow.
>
>
>
> Since ** is a binary operator, it can only accept two arguments.
>
>
>
>
>
> > The Number Protocol specify that the ipow operation ""is the equivalent
>
> > of the Python statement o1 **= o2 when o3 is Py_None, or an in-place
>
> > variant of pow(o1, o2, o3) otherwise.""
>
>
>
> Where is that from?
>
>
>
>
>
> --
>
> Steven

>From The Number Protocol(http://docs.python.org/c-api/number.html).
The full text is:

PyObject* PyNumber_InPlacePower(PyObject *o1, PyObject *o2, PyObject *o3)
Return value: New reference.

**See the built-in function pow().** Returns NULL on failure. The operation is done in-place when o1 supports it. This is the equivalent of the Python statement o1 **= o2 when o3 is Py_None, or an in-place variant of pow(o1, o2, o3) otherwise. If o3 is to be ignored, pass Py_None in its place (passing NULL for o3 would cause an illegal memory access).

The first thing that this text does is referring to the **function** pow, which takes three arguments. And since the documentation of the operator module states that "The operator module exports a set of efficient functions corresponding to the intrinsic operators of Python.", I'd expect the ipow to have three arguments, the third being optional.


With normal exponentiation you have ** referring to the 2-argument variant, and "pow" providing the ability to use the third argument.
At the moment in-place exponentiation you have "**=" referring to the 2-argument variant(and this is consistent), while operator.ipow also referring to it. So providing an ipow with the third argument would just increase consistency in the language, and provide a feature that at the moment is not present. (well if the designers of python care really much about consistency they'd probably add an "ipow" built-in function, so that you don't have to import it from "operator").

I understand that it's not a feature often used, but I can't see why not allowing it.
At the moment you can do that from the C side, because you can call PyNumber_InPlacePower directly, but from the python side you have no way to do that, except for writing a C-extension that wraps the PyNumber_InPlacePower function.
--
http://mail.python.org/mailman/listinfo/python-list


steve+comp.lang.python at pearwood

Aug 12, 2012, 4:03 AM

Post #4 of 8 (884 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

On Sun, 12 Aug 2012 00:14:27 -0700, Giacomo Alzetta wrote:

> From The Number Protocol(http://docs.python.org/c-api/number.html). The
> full text is:
>
> PyObject* PyNumber_InPlacePower(PyObject *o1, PyObject *o2, PyObject
> *o3)
> Return value: New reference.
>
> **See the built-in function pow().** Returns NULL on failure. The
> operation is done in-place when o1 supports it. This is the
> equivalent of the Python statement o1 **= o2 when o3 is Py_None, or
> an in-place variant of pow(o1, o2, o3) otherwise. If o3 is to be
> ignored, pass Py_None in its place (passing NULL for o3 would cause
> an illegal memory access).
>
> The first thing that this text does is referring to the **function**
> pow, which takes three arguments. And since the documentation of the
> operator module states that "The operator module exports a set of
> efficient functions corresponding to the intrinsic operators of
> Python.", I'd expect the ipow to have three arguments, the third being
> optional.

Why? There is no three-argument operator. There is a three-argument
function, pow, but you don't need the operator module for that, it is
built-in. There is no in-place three-argument operator, and no in-place
three-argument function in the operator module.

Arguing from "consistency" is not going to get you very far, since it is
already consistent:

In-place binary operator: **=
In-place binary function: operator.ipow

In-place three-argument operator: none
In-place three-argument function: none

If you decide to make a feature-request, you need to argue from
usefulness, not consistency.

http://bugs.python.org

Remember that the Python 2.x branch is now in feature-freeze, so new
features only apply to Python 3.x.


> With normal exponentiation you have ** referring to the 2-argument
> variant, and "pow" providing the ability to use the third argument.

Correct.


> At the moment in-place exponentiation you have "**=" referring to the
> 2-argument variant(and this is consistent), while operator.ipow also
> referring to it.

Correct. Both **= and ipow match the ** operator, which only takes two
arguments.


> So providing an ipow with the third argument would just
> increase consistency in the language,

Consistency with something other than **= would be inconsistency.



> and provide a feature that at the
> moment is not present. (well if the designers of python care really much
> about consistency they'd probably add an "ipow" built-in function, so
> that you don't have to import it from "operator").

Not everything needs to be a built-in function.



--
Steven
--
http://mail.python.org/mailman/listinfo/python-list


giacomo.alzetta at gmail

Aug 12, 2012, 4:55 AM

Post #5 of 8 (885 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

Il giorno domenica 12 agosto 2012 13:03:08 UTC+2, Steven D'Aprano ha scritto:
> On Sun, 12 Aug 2012 00:14:27 -0700, Giacomo Alzetta wrote:
>
>
>
> > From The Number Protocol(http://docs.python.org/c-api/number.html). The
>
> > full text is:
>
> >
>
> > PyObject* PyNumber_InPlacePower(PyObject *o1, PyObject *o2, PyObject
>
> > *o3)
>
> > Return value: New reference.
>
> >
>
> > **See the built-in function pow().** Returns NULL on failure. The
>
> > operation is done in-place when o1 supports it. This is the
>
> > equivalent of the Python statement o1 **= o2 when o3 is Py_None, or
>
> > an in-place variant of pow(o1, o2, o3) otherwise. If o3 is to be
>
> > ignored, pass Py_None in its place (passing NULL for o3 would cause
>
> > an illegal memory access).
>
> >
>
> > The first thing that this text does is referring to the **function**
>
> > pow, which takes three arguments. And since the documentation of the
>
> > operator module states that "The operator module exports a set of
>
> > efficient functions corresponding to the intrinsic operators of
>
> > Python.", I'd expect the ipow to have three arguments, the third being
>
> > optional.
>
>
>
> Why? There is no three-argument operator. There is a three-argument
>
> function, pow, but you don't need the operator module for that, it is
>
> built-in. There is no in-place three-argument operator, and no in-place
>
> three-argument function in the operator module.
>
>
>
> Arguing from "consistency" is not going to get you very far, since it is
>
> already consistent:
>
>
>
> In-place binary operator: **=
>
> In-place binary function: operator.ipow
>
>
>
> In-place three-argument operator: none
>
> In-place three-argument function: none
>
>
>
> If you decide to make a feature-request, you need to argue from
>
> usefulness, not consistency.
>
>
>
> http://bugs.python.org
>
>
>
> Remember that the Python 2.x branch is now in feature-freeze, so new
>
> features only apply to Python 3.x.
>
>
>
>
>
> > With normal exponentiation you have ** referring to the 2-argument
>
> > variant, and "pow" providing the ability to use the third argument.
>
>
>
> Correct.
>
>
>
>
>
> > At the moment in-place exponentiation you have "**=" referring to the
>
> > 2-argument variant(and this is consistent), while operator.ipow also
>
> > referring to it.
>
>
>
> Correct. Both **= and ipow match the ** operator, which only takes two
>
> arguments.
>
>
>
>
>
> > So providing an ipow with the third argument would just
>
> > increase consistency in the language,
>
>
>
> Consistency with something other than **= would be inconsistency.
>
>
>
>
>
>
>
> > and provide a feature that at the
>
> > moment is not present. (well if the designers of python care really much
>
> > about consistency they'd probably add an "ipow" built-in function, so
>
> > that you don't have to import it from "operator").
>
>
>
> Not everything needs to be a built-in function.
>
>
>
>
>
>
>
> --
>
> Steven

Probably I've mixed things up.

What I mean is: when you implement a new type as a C extension you have to provide special methods through the NumberMethods struct. In this struct both the power and in-place power operations have three arguments.
Now, suppose I implement the three argument variant of the in-place power in a class. No user would be able to call my C function with a non-None third argument, while he would be able to call the normal version with the third argument.

This is what I find inconsistent. either provide a way to call also the in-place exponentiation with three arguments, or define it as a binary function.
Having it as a ternary function, but only from the C-side is quite strange.

--
http://mail.python.org/mailman/listinfo/python-list


tjreedy at udel

Aug 12, 2012, 2:53 PM

Post #6 of 8 (884 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

On 8/12/2012 7:55 AM, Giacomo Alzetta wrote:

> What I mean is: when you implement a new type as a C extension you
> have to provide special methods through the NumberMethods struct. In
> this struct both the power and in-place power operations have three
> arguments.

I am not really sure why the latter is true. Probably 'consistency' at
the special method level, with __pow__. As Steven points out, it is not
needed to implement normal Python code.

This is one area of Python where the design is a bit messy. I believe
the very existence of __ipow__ is a matter of consistency than of known
use cases. Guido was not sure which __ixxx__ would ever be needed (for
mutable objects), so he just put them all in.

At the Python level, both __pow__ and __ipow__ are also documented in
the manual as having an optional, third, modulo parameter. __rpow__ is
defined as binary, but that is a mistake

>>> int.__rpow__(3, 5, 4)
1


> Now, suppose I implement the three argument variant of the
> in-place power in a class.

Are you actually planning to do this, or is this purely theoretical?

> No user would be able to call my C
> function with a non-None third argument,

Not true. Whether the function is coded in Python or C
cls.__ipow__(base, exp, mod) # or
base.__ipow__(exp, mod)

> while he would be able to
> call the normal version with the third argument.

That can also be done directly
>>> int.__pow__(5, 3, 4)
1

--
Terry Jan Reedy

--
http://mail.python.org/mailman/listinfo/python-list


giacomo.alzetta at gmail

Aug 14, 2012, 12:14 AM

Post #7 of 8 (877 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

Il giorno domenica 12 agosto 2012 23:53:46 UTC+2, Terry Reedy ha scritto:
>
> Are you actually planning to do this, or is this purely theoretical?
>

Yes, I do plan to implement ipow.

>
> Not true. Whether the function is coded in Python or C
>
> cls.__ipow__(base, exp, mod) # or
>
> base.__ipow__(exp, mod)
>
>
>
> > while he would be able to
>
> > call the normal version with the third argument.

Yes, that's true. But I find that calling a special-method in that way is *really* ugly. I'd think that the pow built-in function was probably inserted to avoid writing base.__pow__(exp, mod).


--
http://mail.python.org/mailman/listinfo/python-list


giacomo.alzetta at gmail

Aug 14, 2012, 12:14 AM

Post #8 of 8 (876 views)
Permalink
Re: in-place exponentiation incongruities [In reply to]

Il giorno domenica 12 agosto 2012 23:53:46 UTC+2, Terry Reedy ha scritto:
>
> Are you actually planning to do this, or is this purely theoretical?
>

Yes, I do plan to implement ipow.

>
> Not true. Whether the function is coded in Python or C
>
> cls.__ipow__(base, exp, mod) # or
>
> base.__ipow__(exp, mod)
>
>
>
> > while he would be able to
>
> > call the normal version with the third argument.

Yes, that's true. But I find that calling a special-method in that way is *really* ugly. I'd think that the pow built-in function was probably inserted to avoid writing base.__pow__(exp, mod).


--
http://mail.python.org/mailman/listinfo/python-list

Python python RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.