Skip to content

Commit

Permalink
⚡️: fast-path skipping conversion
Browse files Browse the repository at this point in the history
Signed-off-by: nstarman <[email protected]>
  • Loading branch information
nstarman committed Dec 11, 2024
1 parent 9811121 commit cfafaff
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 8 deletions.
22 changes: 15 additions & 7 deletions src/quantity/_src/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,20 @@ def _make_same_unit_method(attr):
if array_api_func := getattr(array_api_compat, attr, None):

def same_unit(self, *args, **kwargs):
return replace(self, value=array_api_func(self.value, *args, **kwargs))
return replace(
self,
value=array_api_func(self.value, *args, **kwargs),
_skip_convert=True,
)

else:

def same_unit(self, *args, **kwargs):
return replace(self, value=getattr(self.value, attr)(*args, **kwargs))
return replace(
self,
value=getattr(self.value, attr)(*args, **kwargs),
_skip_convert=True,
)

return same_unit

Expand All @@ -119,7 +127,7 @@ def _make_same_unit_attribute(attr):
attr_getter = getattr(array_api_compat, attr, operator.attrgetter(attr))

def same_unit(self):
return replace(self, value=attr_getter(self.value))
return replace(self, value=attr_getter(self.value), _skip_convert=True)

return property(same_unit)

Expand Down Expand Up @@ -174,7 +182,7 @@ def _operate(self, other, op_func, units_helper):
except Exception:
return NotImplemented
else:
return replace(self, unit=unit)
return replace(self, unit=unit, _skip_convert=True)

other_value, other_unit = get_value_and_unit(other)
self_value = self.value
Expand All @@ -189,7 +197,7 @@ def _operate(self, other, op_func, units_helper):
# Deal with the very unlikely case that other is an array type
# that knows about Quantity, but cannot handle the array we carry.
return NotImplemented
return replace(self, value=value, unit=unit)
return replace(self, value=value, unit=unit, _skip_convert=True)

# Operators (skipping ones that make no sense, like __and__);
# __pow__ and __rpow__ need special treatment and are defined below.
Expand Down Expand Up @@ -238,15 +246,15 @@ def __pow__(self, exp, mod=None):
return NotImplemented

value = operator.__pow__(self.value, exp)
return replace(self, value=value, unit=self.unit**exp)
return replace(self, value=value, unit=self.unit**exp, _skip_convert=True)

def __ipow__(self, exp, mod=None):
exp = _check_pow_args(exp, mod)
if exp is NotImplemented:
return NotImplemented

value = operator.__ipow__(self.value, exp)
return replace(self, value=value, unit=self.unit**exp)
return replace(self, value=value, unit=self.unit**exp, _skip_convert=True)

def __setitem__(self, item, value):
self.value[item] = value_in_unit(value, self.unit)
Expand Down
8 changes: 7 additions & 1 deletion src/quantity/_src/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ def _process_dataclass(cls: type[_CT], **kwargs: Any) -> type[_CT]:

# Ensure that the __init__ method does conversion
@functools.wraps(dcls.__init__) # give it the same signature
def __init__(self, *args: Any, **kwargs: Any) -> None:
def __init__(self, *args: Any, _skip_convert: bool = False, **kwargs: Any) -> None:
# Fast path: no conversion
if _skip_convert:
self.__init__.__wrapped__(self, *args, **kwargs)
return

# Bind the arguments to the signature
ba = self.__init__._obj_signature_.bind_partial(*args, **kwargs)
ba.apply_defaults() # so eligible for conversion

Expand Down

0 comments on commit cfafaff

Please sign in to comment.