I tried to collect some of my formulas inside classes so that I didn't need to browser the names of the functions anymore but only determine which Quantity I want to calculate and then check which methods are avaiable for determining it. This is based on the astropy.units module. Just to make a small example:import astropy.units as uclass Length(object):    unit = u.m    @classmethod    #@quantitydecorator # I'll explain this later    def from_velocity_time(cls, velocity, time):                Calculate length from a given velocity and time.        Parameters        ----------        velocity: `astropy.units.Quantity`            The velocity of the object.        time: `astropy.units.Quantity`            The time the object moved at this velocity        Returns        -------        length: `astropy.units.Quantity`            The determined length based on velocity * time                return velocity * timeThis works great, I tried:Length.from_velocity_time(100*u.km/u.h, 100*u.h)# gives 10000 kmbut has some downsides when the units are equivalent but different:Length.from_velocity_time(100*u.km/u.s, 100*u.h)# 10000 h*km/sso I decided to create a general decorator that converts the results unit to the unit defined in the class or have an additional parameter result_unit for every method call:def quantitydecorator(f):        Allows for an extra argument result_unit for all methods    and converts the result to the unit specified there or if not     given to the unit specified in the class.        @wraps(f)    def wrapper(*args, **kwds):        # Check if result_unit is given otherwise use the class default         # (args[0] is the class)        if 'result_unit' in kwds:            result_unit = u.Unit(kwds.pop('result_unit'))        else:            result_unit = args[0].unit        # Calculate the result        result = f(*args, **kwds)        # Convert to result unit if the result has a unit        if not hasattr(result, 'unit'):            # No unit attribute so we have a plain numpy array            # or number, only let it pass when target unit is            # dimensionless            if args[0].unit != u.dimensionless_unscaled:                raise ValueError('Got dimensionless quantity but needed'                        ' quantity with unit: {0}'.format(args[0].unit))        # Result has a different unit than wanted, convert it to wanted unit        elif result.unit != result_unit:            result = result.to(result_unit)        return result    return wrapperThis works fine (this time the decorator must be uncommented in the class):Length.from_velocity_time(100*u.km/u.s, 100*u.h)# 3.6e10mLength.from_velocity_time(100*u.km/u.s, 100*u.h, result_unit=u.AU)# 0.24064514AUbut I can't help suspecting that this is rather awkward. I'm using approximately 300 functions but there are only around 30-40 parameters (like Length in the example but more sophisticated like free-fall-time, half-light-radius. redshift, etc. everything that I at some point needed for any calculation and there are typically 2-10 ways to calculate such a Quantity) so it would be a great gain to collect them into classes and don't have duplicate logic with the result_unit. Would you consider this good coding style or should I dismiss this attempt and choose a different approach (if so, any idea which)?
Decorator to convert a function's result into the desired units
python;converting;meta programming;astropy
Your proposalLength.from_velocity_time(100*u.km/u.s, 100*u.h, result_unit=u.AU) is less conventional and not any better thanLength.from_velocity_time(100*u.km/u.s, 100*u.h).to(u.AU)In addition, monkey-patching the from_velocity_time() function to support a special result_unit named parameter feels slimy.The only drawback with .to() is that pure numbers wouldn't support such a method.  But that would mean that the calculation is complete nonsense anyway.