Finalizes the masked array.
(self, obj)
| 3048 | self.__dict__.update(_optinfo) |
| 3049 | |
| 3050 | def __array_finalize__(self, obj): |
| 3051 | """ |
| 3052 | Finalizes the masked array. |
| 3053 | |
| 3054 | """ |
| 3055 | # Get main attributes. |
| 3056 | self._update_from(obj) |
| 3057 | |
| 3058 | # We have to decide how to initialize self.mask, based on |
| 3059 | # obj.mask. This is very difficult. There might be some |
| 3060 | # correspondence between the elements in the array we are being |
| 3061 | # created from (= obj) and us. Or there might not. This method can |
| 3062 | # be called in all kinds of places for all kinds of reasons -- could |
| 3063 | # be empty_like, could be slicing, could be a ufunc, could be a view. |
| 3064 | # The numpy subclassing interface simply doesn't give us any way |
| 3065 | # to know, which means that at best this method will be based on |
| 3066 | # guesswork and heuristics. To make things worse, there isn't even any |
| 3067 | # clear consensus about what the desired behavior is. For instance, |
| 3068 | # most users think that np.empty_like(marr) -- which goes via this |
| 3069 | # method -- should return a masked array with an empty mask (see |
| 3070 | # gh-3404 and linked discussions), but others disagree, and they have |
| 3071 | # existing code which depends on empty_like returning an array that |
| 3072 | # matches the input mask. |
| 3073 | # |
| 3074 | # Historically our algorithm was: if the template object mask had the |
| 3075 | # same *number of elements* as us, then we used *it's mask object |
| 3076 | # itself* as our mask, so that writes to us would also write to the |
| 3077 | # original array. This is horribly broken in multiple ways. |
| 3078 | # |
| 3079 | # Now what we do instead is, if the template object mask has the same |
| 3080 | # number of elements as us, and we do not have the same base pointer |
| 3081 | # as the template object (b/c views like arr[...] should keep the same |
| 3082 | # mask), then we make a copy of the template object mask and use |
| 3083 | # that. This is also horribly broken but somewhat less so. Maybe. |
| 3084 | if isinstance(obj, ndarray): |
| 3085 | # XX: This looks like a bug -- shouldn't it check self.dtype |
| 3086 | # instead? |
| 3087 | if obj.dtype.names is not None: |
| 3088 | _mask = getmaskarray(obj) |
| 3089 | else: |
| 3090 | _mask = getmask(obj) |
| 3091 | |
| 3092 | # If self and obj point to exactly the same data, then probably |
| 3093 | # self is a simple view of obj (e.g., self = obj[...]), so they |
| 3094 | # should share the same mask. (This isn't 100% reliable, e.g. self |
| 3095 | # could be the first row of obj, or have strange strides, but as a |
| 3096 | # heuristic it's not bad.) In all other cases, we make a copy of |
| 3097 | # the mask, so that future modifications to 'self' do not end up |
| 3098 | # side-effecting 'obj' as well. |
| 3099 | if (_mask is not nomask and obj.__array_interface__["data"][0] |
| 3100 | != self.__array_interface__["data"][0]): |
| 3101 | # We should make a copy. But we could get here via astype, |
| 3102 | # in which case the mask might need a new dtype as well |
| 3103 | # (e.g., changing to or from a structured dtype), and the |
| 3104 | # order could have changed. So, change the mask type if |
| 3105 | # needed and use astype instead of copy. |
| 3106 | if self.dtype == obj.dtype: |
| 3107 | _mask_dtype = _mask.dtype |
no test coverage detected