@@ -38,28 +38,24 @@ class Quantity(numpy.ndarray):
3838 __array_priority__ = 21
3939
4040 def __new__ (cls , data , units = '' , dtype = 'd' , copy = True ):
41- if not isinstance (data , numpy .ndarray ):
42- data = numpy .array (data , dtype = dtype )
43-
44- if copy == True :
45- data = data .copy ()
41+ if isinstance (data , Quantity ):
42+ if units :
43+ # force a copy so we don't rescale a subset of the original
44+ copy = True
45+
46+ res = numpy .array (data , dtype = dtype , copy = copy ).view (cls )
47+ if copy :
48+ res ._dimensionality = data ._dimensionality .copy ()
49+ else :
50+ res ._dimensionality = data ._dimensionality
51+ if units :
52+ res .units = units
4653
47- if isinstance (data , Quantity ) and units :
48- data = data .rescale (units )
54+ return res
4955
50- # should this be a "cooperative super" call instead?
51- ret = numpy .ndarray .__new__ (
52- cls ,
53- data .shape ,
54- data .dtype ,
55- buffer = data
56- )
57- return ret
56+ res = numpy .array (data , dtype = dtype , copy = copy ).view (cls )
5857
59- def __init__ (self , data , units = '' , dtype = 'd' , copy = True ):
60- if not units and isinstance (data , Quantity ):
61- dims = data .dimensionality
62- elif isinstance (units , str ):
58+ if isinstance (units , str ):
6359 if units in ('' , 'dimensionless' ):
6460 dims = {}
6561 else :
@@ -73,7 +69,9 @@ def __init__(self, data, units='', dtype='d', copy=True):
7369 'units must be a quantity, string, or dimensionality, got %s' \
7470 % type (units )
7571 )
76- self ._dimensionality = Dimensionality (dims )
72+ res ._dimensionality = Dimensionality (dims )
73+
74+ return res
7775
7876 @property
7977 def dimensionality (self ):
@@ -116,30 +114,76 @@ def rescale(self, units):
116114 """
117115 Return a copy of the quantity converted to the specified units
118116 """
119- copy = Quantity (self )
120- copy .units = units
121- return copy
117+ return Quantity (self , units )
122118
123119 @property
124120 def simplified (self ):
125121 rq = 1 * unit_registry ['dimensionless' ]
126122 for u , d in self .dimensionality .iteritems ():
127- rq *= u .reference_quantity ** d
123+ rq = rq * u .reference_quantity ** d
128124 return rq * self .magnitude
129125
130126 def __array_finalize__ (self , obj ):
131- self ._dimensionality = getattr (
132- obj , 'dimensionality' , Dimensionality ()
133- )
127+ self ._dimensionality = getattr (obj , '_dimensionality' , Dimensionality ())
128+ if self .base is None :
129+ self ._dimensionality = self ._dimensionality .copy ()
130+
131+ # def __array_wrap__(self, obj, context=None):
132+ # """
133+ # Special hook for ufuncs.
134+ # Wraps the numpy array and sets the mask according to context.
135+ # """
136+ # result = obj.view(type(self))
137+ #
138+ # if context is not None:
139+ # result._dimensionality = result._dimensionality.copy()
140+ # (func, args, _) = context
141+ # m = reduce(mask_or, [getmaskarray(arg) for arg in args])
142+ # # Get the domain mask................
143+ # domain = ufunc_domain.get(func, None)
144+ # if domain is not None:
145+ # if len(args) > 2:
146+ # d = reduce(domain, args)
147+ # else:
148+ # d = domain(*args)
149+ # # Fill the result where the domain is wrong
150+ # try:
151+ # # Binary domain: take the last value
152+ # fill_value = ufunc_fills[func][-1]
153+ # except TypeError:
154+ # # Unary domain: just use this one
155+ # fill_value = ufunc_fills[func]
156+ # except KeyError:
157+ # # Domain not recognized, use fill_value instead
158+ # fill_value = self.fill_value
159+ # result = result.copy()
160+ # np.putmask(result, d, fill_value)
161+ # # Update the mask
162+ # if m is nomask:
163+ # if d is not nomask:
164+ # m = d
165+ # else:
166+ # m |= d
167+ # # Make sure the mask has the proper size
168+ # if result.shape == () and m:
169+ # return masked
170+ # else:
171+ # result._mask = m
172+ # result._sharedmask = False
173+ # #....
174+ # return result
134175
135176 def __add__ (self , other ):
136177 if not isinstance (other , Quantity ):
137178 other = Quantity (other , copy = False )
138179
139180 dims = self .dimensionality + other .dimensionality
140- magnitude = self .magnitude + other .magnitude
181+ ret = super (Quantity , self ).__add__ (other )
182+ ret ._dimensionality = dims
141183
142- return Quantity (magnitude , dims , magnitude .dtype )
184+ return ret
185+
186+ # TODO: in-place arithmetic should check for .base, and raise if not None
143187
144188 def __iadd__ (self , other ):
145189 if not isinstance (other , Quantity ):
@@ -187,12 +231,13 @@ def __rsub__(self, other):
187231 def __mul__ (self , other ):
188232 try :
189233 dims = self .dimensionality * other .dimensionality
190- magnitude = self .magnitude * other .magnitude
191234 except AttributeError :
192- magnitude = self . magnitude * other
193- dims = copy . copy (self .dimensionality )
235+ other = Quantity ( other , copy = False )
236+ dims = Dimensionality (self .dimensionality )
194237
195- return Quantity (magnitude , dims , magnitude .dtype )
238+ ret = super (Quantity , self ).__mul__ (other )
239+ ret ._dimensionality = dims
240+ return ret
196241
197242 def __imul__ (self , other ):
198243 try :
@@ -211,12 +256,13 @@ def __rmul__(self, other):
211256 def __truediv__ (self , other ):
212257 try :
213258 dims = self .dimensionality / other .dimensionality
214- magnitude = self .magnitude / other .magnitude
215259 except AttributeError :
216- magnitude = self . magnitude / other
217- dims = copy . copy (self .dimensionality )
260+ other = Quantity ( other , copy = False )
261+ dims = Dimensionality (self .dimensionality )
218262
219- return Quantity (magnitude , dims , magnitude .dtype )
263+ ret = super (Quantity , self ).__truediv__ (other )
264+ ret ._dimensionality = dims
265+ return ret
220266
221267 def __div__ (self , other ):
222268 return self .__truediv__ (other )
0 commit comments