Curious behavior of __radd__
Hi all,
here's something I don't understand. Consider the following code snippet:
---------------------------------------------------
class A(object):
def __radd__(self, other):
print(type(other))
import numpy as np
np.complex64(1j) + A()
---------------------------------------------------
In my world, this should print
On Wed, Feb 1, 2012 at 12:26 PM, Andreas Kloeckner
Hi all,
here's something I don't understand. Consider the following code snippet:
--------------------------------------------------- class A(object): def __radd__(self, other): print(type(other))
import numpy as np np.complex64(1j) + A() ---------------------------------------------------
In my world, this should print
. It does print . Who is casting my sized complex to a built-in complex, and why?
It can be Python's type coercion, because the behavior is the same in Python 3.2. (And the docs say Python 3 doesn't support coercion.)
It gets called once for every scalar in the array, or in your case, just the scalar, and the scalars are converted to python types for the call. At least, that is what it looks like. Chuck
This seems odd to me. Unraveling what is going on (so far): Let a = np.complex64(1j) and b = A() * np.complex64.__add__ is calling np.add * np.add(a, b) needs to search for an "add" loop that matches the input types and it finds one with signature ('O', 'O') -> 'O' * a is converted to an array via the equivalent of a1 = array(a,'O') * b is converted to an array in the same way b1 = array(b, 'O') Somehow a1 as an array of objects is an array of "complex" types instead of "complex64" types Then the equivalent of a1[()] + b1[()] is called. So, the conversion is being done by a1 = array(a, 'O') I don't know why this is. This seems like a regression, but I don't have an old version of NumPy to check. compare: type(a) type(np.array(a,'O')[()]) These should be the same type. But they are not... -Travis On Feb 1, 2012, at 1:26 PM, Andreas Kloeckner wrote:
Hi all,
here's something I don't understand. Consider the following code snippet:
--------------------------------------------------- class A(object): def __radd__(self, other): print(type(other))
import numpy as np np.complex64(1j) + A() ---------------------------------------------------
In my world, this should print
. It does print . Who is casting my sized complex to a built-in complex, and why?
It can be Python's type coercion, because the behavior is the same in Python 3.2. (And the docs say Python 3 doesn't support coercion.)
(Please cc me.)
Thanks, Andreas _______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
Hey Andreas, As previously described: what changes the type of np.complex64(1j) during the A() call is that when a is an array scalar it is converted to an object array because that is the only signature that matches. During this conversion, what is extracted from the object array is piped through the equivalent of .item() which tries to map to a standard Python object. It must be different to break the infinite recursion that would otherwise get setup as the ufunc registered for "Object" loops just calls PyNumber_Add with the extracted objects. If the extracted object were again the original array scalar, it's __add__ method would be called, which would just call back into the ufunc machinery setting up the cycle again... I've confirmed this has been the behavior since at least 1.4.x. So, it's not a regression. It is actually intentionally to avoid the recursion. The proper fix is to add actual scalar math methods instead of re-using the ufunc machinery for the array scalars (this would be much faster as well...) -Travis On Feb 1, 2012, at 1:26 PM, Andreas Kloeckner wrote:
Hi all,
here's something I don't understand. Consider the following code snippet:
--------------------------------------------------- class A(object): def __radd__(self, other): print(type(other))
import numpy as np np.complex64(1j) + A() ---------------------------------------------------
In my world, this should print
. It does print . Who is casting my sized complex to a built-in complex, and why?
It can be Python's type coercion, because the behavior is the same in Python 3.2. (And the docs say Python 3 doesn't support coercion.)
(Please cc me.)
Thanks, Andreas _______________________________________________ NumPy-Discussion mailing list NumPy-Discussion@scipy.org http://mail.scipy.org/mailman/listinfo/numpy-discussion
participants (3)
-
Andreas Kloeckner
-
Charles R Harris
-
Travis Oliphant