Python Unit Coversion Code Optimization in terms of Space and Time Complexity

Ok I am making unit converter and I have attached temperature conversion code below. The problem with this code I think is that I have written function for each and every single unit to convert to another unit.

So in code below there is one function to covert Celsius into Fahrenheit, Kelvin, Renkien and Newton. Then another function to convert Fahrenheit to Celsius,Kelvin, Renkien and Newton.

Now I do understand that every unit is related to one another. But I just can't think of a way if this conversion can be done using single function such that first you choose your source and then destination and using that without using five different function I can just finish in one.

Another way I thought of this was I can may be use dictionaries rather then using so many if else conditions but I would like know which one is more optimized in terms of both time and space complexity.

class TempConv:

def __init__(self,source,dest,val):
self.frm=source
self.to=dest
self.x=val
self.ans=0

def setFrm(self,arg):
self.frm=arg

def setTo(self,arg):
self.to=arg

def setX(self,arg):
self.x=arg

def calculate(self):
if self.x is "celc":
self.ans=self.celcToAny()
elif self.x is "farh":
self.ans=self.farhToAny()
elif self.x is "kel":
self.ans=self.kelToAny()
elif self.x is "renk":
self.ans=self.renkToAny()
elif self.x is "newt":
self.ans=self.newtToAny()
else:
self.ans=self.x

#Celcius to Any
def celcToAny(self):
if self.to is "farh":
return (float(self.x)*1.8)+32
elif self.to is "kel":
return float(self.x)+273.15
elif self.to is "renk":
return (flaot(self.x)+273.15)*1.8
elif self.to is "newt":
return float(self.x)*0.33
else:
return self.x

#Fahrenheit to Any
def fahrToAny(self):
if self.to is "celc":
return (float(self.x)-32)*0.555555556
elif self.to is "kel":
return (float(self.x)+459.67)*0.555555556
elif self.to is "renk":
return float(self.x)+459.67
elif self.to is "newt":
return (float(self.x)-32)*0.183333333
else:
return self.x

#Kelvin to Any
def kelToAny(self):
if self.to is "farh":
return (float(self.x)*1.8)-459.67;
elif self.to is "celc":
return float(self.x)-273.15
elif self.to is "renk":
return float(self.x)*1.8
elif self.to is "newt":
return (float(self.x)-273.15)*0.33
else:
return self.x

#Rankine to Any
def renkToAny(self):
if self.to is "farh":
return float(self.x)-459.67;
elif self.to is "celc":
return (float(self.x)-491.67)*0.555555556
elif self.to is "kel":
return float(self.x)*0.555555556
elif self.to is "newt":
return (float(self.x)-491.67)0.183333333
else:
return self.x

#Newton to Any
def newtToAny(self):
if self.to is "farh":
return (float(self.x)*5.454545455)+32
elif self.to is "kel":
return (float(self.x)*3.030303030)+273.15
elif self.to is "renk":
return (flaot(self.x)*5.454545455)+491.67
elif self.to is "celc":
return float(self.x)*3.030303030
else:
return self.x
• Does x have to remain constant? – flakes Mar 24 '14 at 18:53

There is not much need for a class for what you are after. Storing all the conversion factors in a dictionary, you could simply do something like:

def convert_temp(val, from_, to_):
if from_ == to_:
return val
off1, mult, off2 = convert_temp.data[from_][to_]
return (val + off1) * mult + off2
convert_temp.data = {'C' : {'F' : (0, 1.8, 32)},
'F' : {'C' : (-32, 0.555555556, 0)}}

And now:

>>> convert_temp(50, 'C', 'F')
122.0
>>> convert_temp(122, 'F', 'C')
50.000000039999996

You would of course have a larger dictionary with all possible conversions. You could get fancy and store only half the conversions:

def convert_temp2(val, from_, to_):
if from_ == to_:
return val
try:
off1, mult, off2 = convert_temp2.data[from_][to_]
except KeyError:
off2, mult, off1 = convert_temp2.data[to_][from_]
off1 = -off1
off2 = -off2
mult = 1 / mult
return (val + off1) * mult + off2
convert_temp2.data = {'C' : {'F' : (0, 1.8, 32)}}

>>> convert_temp2(50, 'C', 'F')
122.0
>>> convert_temp2(122, 'F', 'C')
50.0

I would probably choose one type as the standard type of which I convert all types to as an intermediate step, to cut down on code.

def farhTocelc(self):
self.setFrm("celc")
self.x = (float(self.x)-32)*0.555555556
def kelTocalc(self):
self.setFrm("celc")
self.x =  float(self.x)-273.15
def renkTocelc(self):
self.setFrm("celc")
self.x =  (float(self.x)-491.67)*0.555555556
def newtTocelc(self):
self.setFrm("celc")
self.x =  float(self.x)*3.030303030
def celcTocelc(self):
self.setFrm("celc")
self.x =  float(self.x)

def celcTofarh(self):
self.setFrm("farh")
self.x =  (float(self.x)*1.8)+32.0
def celcTokel(self):
self.setFrm("kel")
self.x =  float(self.x)+273.15
def celcTorenk(self):
self.setFrm("renk")
self.x =  (float(self.x)+273.15)*1.8
def celcTonewt(self):
self.setFrm("newt")
self.x =  float(self.x)*0.33

Then have the init, setTo, and setFrm functions change the values of to and frm functions instead of strings.

def __init__(self,source,dest,val):
self.setFrm(source)
self.setTo(dest)
self.x = val
self.ans = 0

def setFrm(self,arg):
if arg + "Tocelc" in locals().keys():
self.frm = locals()[arg + "Tocelc"]
else:
raise Exception("invalid source")

def setTo(self,arg):
if arg + "Tocelc" in locals().keys():
self.to = locals()["celcTo"+arg]
else:
raise Exception("invalid dest")

Now in calculate you can just do

def calculate(self):
self.frm()
self.to()