[NumPy-Tickets] [NumPy] #1426: subclasses of ndarray have problems with reflected operations in python 3
NumPy Trac
numpy-tickets@scipy....
Thu Mar 11 15:57:08 CST 2010
#1426: subclasses of ndarray have problems with reflected operations in python 3
------------------------+---------------------------------------------------
Reporter: DarrenDale | Owner: somebody
Type: defect | Status: new
Priority: high | Milestone: 2.0.0
Component: numpy.core | Version: devel
Keywords: python-3 |
------------------------+---------------------------------------------------
Quoting a discussion on the mailing list, where Pauli V. explained the
reasons for the reported behavior:
>> Now that the trunk has some support for python3, I am working on making
Quantities work with python3 as well. I'm running into some problems
related to subclassing ndarray that can be illustrated with a simple
script, reproduced below. It looks like there is a problem with the
reflected operations, I see problems with __rmul__ and __radd__, but not
with __mul__ and __add__:
>
>Thanks for testing. I wish the test suite was more complete (hint! hint!
:)
>
>Yes, Python 3 introduced some semantic changes in how subclasses of
builtin classes (= written in C) inherit the __r*__ operations.
>
>Below I'll try to explain what is going on. We probably need to change
some things to make things work better on Py3, within the bounds we are
able to.
>
>Suggestions are welcome. The most obvious one could be to explicitly
implement __rmul__ etc. on Python 3.
{{{
import numpy as np
class A(np.ndarray):
def __new__(cls, *args, **kwargs):
return np.ndarray.__new__(cls, *args, **kwargs)
class B(A):
def __mul__(self, other):
return self.view(A).__mul__(other)
def __rmul__(self, other):
return self.view(A).__rmul__(other)
def __add__(self, other):
return self.view(A).__add__(other)
def __radd__(self, other):
return self.view(A).__radd__(other)
a = A((10,))
b = B((10,))
print('A __rmul__:')
print(a.__rmul__(2))
# yields NotImplemented
print(a.view(np.ndarray).__rmul__(2))
# yields NotImplemented
}}}
>Correct. ndarray does not implement __rmul__, but relies on an automatic
wrapper generated by Python.
>
>The automatic wrapper (wrap_binaryfunc_r) does the following:
>
>1. Is `type(other)` a subclass of `type(self)`? If yes, call __mul__ with
swapped arguments.
>2. If not, bail out with NotImplemented.
>
>So it bails out.
>
>Previously, the ndarray type had a flag that made Python to skip the
subclass check. That does not exist any more on Python 3, and is the root
of this issue.
{{{
print(2*a)
# ok !!??
}}}
>Here, Python checks
>
>1. Does nb_multiply from the left op succeed? Nope, since floats don't
know how to multiply ndarrays.
>
>2. Does nb_multiply from the right op succeed? Here the execution passes
*directly* to array_multiply, completely skipping the __rmul__ wrapper.
>
>Note also that in the C-level number protocol there is only a single
multiplication function for both left and right multiplication.
>
{{{
print('B __rmul__:')
print(b.__rmul__(2))
# yields NotImplemented
print(b.view(A).__rmul__(2))
# yields NotImplemented
print(b.view(np.ndarray).__rmul__(2))
# yields NotImplemented
print(2*b)
# yields: TypeError: unsupported operand type(s) for *: 'int' and 'B'
}}}
>But here, the subclass calls the wrapper ndarray.__rmul__, which wants to
be careful with types, and hence fails.
>
>Yes, probably explicitly defining __rmul__ for ndarray could be the
>right solution. Please file a bug report on this.
--
Ticket URL: <http://projects.scipy.org/numpy/ticket/1426>
NumPy <http://projects.scipy.org/numpy>
My example project
More information about the NumPy-Tickets
mailing list