Refactoring a converter using enums

Viewed 24

I have this temperature converter:

def temperature_converter(scale, to_scale, temperature):
    scale = scale.capitalize()
    to_scale = to_scale.capitalize()
    if scale == 'F' and to_scale == 'C':
        return (temperature * 1.8) + 32
    elif scale == 'C' and to_scale == 'F':
        return (5 / 9) * (temperature - 32)
    elif scale == 'K' and to_scale == 'F':
        return (9 / 5) * (temperature - 273) + 32
    elif scale == 'F' and to_scale == 'K':
        return (5 / 9) * (temperature - 32) + 273
    elif scale == 'C' and to_scale == 'K':
        return temperature + 273
    elif scale == 'K' and to_scale == 'C':
        return temperature - 273

That is not that elegant, but gets the job done.

The task is to refactor it in a more elegant method, using enums and the relations between temperature scales.

I did some googling and i kinda get how to use enums but don't get how to do it in this situation.

This is what i have for now:

class Scales(Enum):
    Celsius = 'C'
    Fahrenheit = 'F'
    Kelvin = 'K'


def temp_conv_2(scale, to_scale_, temp):
    scale = scale.capitalize()
    to_scale_ = to_scale_.capitalize()
    for scale in Scales:
        if scale == Scales.Celsius and to_scale_ == Scales.Fahrenheit:
            return (5 / 9) * (temp - 32)

What logic should i be using to avoid so many ifs and solve this problem?

1 Answers

Here's an approach:

  • define each scale by reference to Kelvin: its zero point in K°, and how many K° correspond to 1 degree in the scale
  • use those values to convert to and from Kelvin
  • convert between two non-Kelvin scales by converting source to Kelvin and then Kelvin to target

I added the Reaumur scale, you may want to add others as in this Wikipedia article

from dataclasses import dataclass

@dataclass
class Scale:
    name : str
    k_zero : float
    k_degree : float

class ScaleConverter:
    def __init__(self):
        self.scales = {}
        self.scales['K'] = Scale('Kelvin', 0.0, 1.0)
        self.scales['C'] = Scale('Celsius', 273.15, 1.0)
        self.scales['F'] = Scale('Fahrenheit', 459.67, 1.8)
        self.scales['R'] = Scale('Reaumur', 273.15, 0.8)
        
    def convert(self, temp, from_scale, to_scale):
        if from_scale == to_scale:
            return temp
        if from_scale == 'K' or to_scale == 'K':
            delta = self.scales[from_scale].k_zero - self.scales[to_scale].k_zero
            coeff = self.scales[to_scale].k_degree / self.scales[from_scale].k_degree
            print(temp, coeff, delta)
            if coeff > 1:
                result = round(temp * coeff + delta, 2)
            elif coeff < 1:
                result = round((temp + delta) * coeff, 2)
            else:
                result = round(temp + delta, 2)
            return result
        else:
            return self.convert(self.convert(temp, from_scale, 'K'), 'K', to_scale)

Note: I didn't use an enum because I don't like to have enum values as arguments to function. But you may of course define one.

Related