summaryrefslogtreecommitdiff
path: root/numpy/ma/core.py
diff options
context:
space:
mode:
authorCharles Harris <charlesr.harris@gmail.com>2017-09-21 13:42:43 -0500
committerGitHub <noreply@github.com>2017-09-21 13:42:43 -0500
commit1ccfa62d8ac3f25deab22e415ccc5fe8a7d75ab4 (patch)
tree6cb2b62d71361c374a63a974ee6341e2f754ab89 /numpy/ma/core.py
parent92d08dbcc9f489e54aeab8525b4b30f7b5d01ecf (diff)
parentd4509fc5e46708e047fb8de98b6eb88d53a9bc74 (diff)
downloadnumpy-1ccfa62d8ac3f25deab22e415ccc5fe8a7d75ab4.tar.gz
Merge pull request #9336 from eric-wieser/masked-constant
BUG: Fix various problems with the np.ma.masked constant
Diffstat (limited to 'numpy/ma/core.py')
-rw-r--r--numpy/ma/core.py67
1 files changed, 55 insertions, 12 deletions
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index d8d3ae621..eceb81269 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -6180,17 +6180,40 @@ isMA = isMaskedArray # backward compatibility
class MaskedConstant(MaskedArray):
- # We define the masked singleton as a float for higher precedence.
- # Note that it can be tricky sometimes w/ type comparison
- _data = data = np.array(0.)
- _mask = mask = np.array(True)
- _baseclass = ndarray
+ # the lone np.ma.masked instance
+ __singleton = None
+
+ def __new__(cls):
+ if cls.__singleton is None:
+ # We define the masked singleton as a float for higher precedence.
+ # Note that it can be tricky sometimes w/ type comparison
+ data = np.array(0.)
+ mask = np.array(True)
+
+ # prevent any modifications
+ data.flags.writeable = False
+ mask.flags.writeable = False
- def __new__(self):
- return self._data.view(self)
+ # don't fall back on MaskedArray.__new__(MaskedConstant), since
+ # that might confuse it - this way, the construction is entirely
+ # within our control
+ cls.__singleton = MaskedArray(data, mask=mask).view(cls)
+
+ return cls.__singleton
def __array_finalize__(self, obj):
- return
+ if self.__singleton is None:
+ # this handles the `.view` in __new__, which we want to copy across
+ # properties normally
+ return super(MaskedConstant, self).__array_finalize__(obj)
+ elif self is self.__singleton:
+ # not clear how this can happen, play it safe
+ pass
+ else:
+ # everywhere else, we want to downcast to MaskedArray, to prevent a
+ # duplicate maskedconstant.
+ self.__class__ = MaskedArray
+ MaskedArray.__array_finalize__(self, obj)
def __array_prepare__(self, obj, context=None):
return self.view(MaskedArray).__array_prepare__(obj, context)
@@ -6202,16 +6225,36 @@ class MaskedConstant(MaskedArray):
return str(masked_print_option._display)
def __repr__(self):
- return 'masked'
-
- def flatten(self):
- return masked_array([self._data], dtype=float, mask=[True])
+ if self is self.__singleton:
+ return 'masked'
+ else:
+ # it's a subclass, or something is wrong, make it obvious
+ return object.__repr__(self)
def __reduce__(self):
"""Override of MaskedArray's __reduce__.
"""
return (self.__class__, ())
+ # inplace operations have no effect. We have to override them to avoid
+ # trying to modify the readonly data and mask arrays
+ def __iop__(self, other):
+ return self
+ __iadd__ = \
+ __isub__ = \
+ __imul__ = \
+ __ifloordiv__ = \
+ __itruediv__ = \
+ __ipow__ = \
+ __iop__
+ del __iop__ # don't leave this around
+
+ def copy(self, *args, **kwargs):
+ """ Copy is a no-op on the maskedconstant, as it is a scalar """
+ # maskedconstant is a scalar, so copy doesn't need to copy. There's
+ # precedent for this with `np.bool_` scalars.
+ return self
+
masked = masked_singleton = MaskedConstant()
masked_array = MaskedArray