Reputation: 116
Probably this can't be done the way I would like. I was making a class Temperature
in python.
I would like to set a property called temperature
and set or retrieve its value on different scales like Kevin, Celsius or Fahrenheit.
Set temperature:
T = Temperature()
T.temperature = 20 # Set temperature to 20ºC
T.temperature('Fahrenheit') = 68 # Set temperature to 68ºF
T.temperature('Kelvin') = 305 # Set temperature to 305K
Get temperature:
t = T.temperature # retrieves temperature in Celsius
t = T.temperature('Fahrenheit') # retrieves temperature in Fahrenheit
t = T.temperature('Kelvin') # retrieves temperature in Kelvin
I have this code. Firstly I tried to use @property
decorator but it was not working. Then I decided to move to traditional syntax using x=property(x_get, x_set)
class Temperature:
def __init__(self, temperature:float = 0, scale:str = "Celsius"):
# All temperatures will be stored as KELVIN
self._temperature = None
self.set_temperature(temperature, scale)
def get_temperature(self, scale: str = "Celsius"):
converter = {
"Celsius": self._temperature - 273.15,
"Fahrenheit": ((self._temperature - 273.15) * 1.8) + 32,
"Kelvin": self._temperature
}
value = converter.get(scale)
return value
def set_temperature(self, value: float, scale: str = "Celsius"):
converter = {
"Celsius": value + 273.15,
"Fahrenheit": (value - 32) / 1.8 + 273.15,
"Kelvin": value
}
self._temperature = converter.get(scale)
if self._temperature < 0 :
self._temperature = None
raise ValueError("Temperature below 0 Kelvin is not possible")
temperature = property(get_temperature, set_temperature)
But I cannot use the proposed syntax; although using traditional syntax seems to be a good approach.
It works when calling to property temperature
without any parameters or directly to get and set methods with parameters:
>>> T = Temperature(20) # Initialize
>>> T.temperature # Getter
20.0
>>> T.temperature=30 # Setter
>>> T.temperature # Getter
30.0
It works if I call directly to get_temperature
or set_temperature
>>> T.get_temperature("Fahrenheit")
86.0
But if I call to getter or setter property with parameter it raises an error:
T.temperature("Fahrenheit")
Traceback (most recent call last):
File "<input>", line 1, in <module>
TypeError: 'float' object is not callable
Or
T.temperature("Kelvin") = 301.15
File "<input>", line 1
SyntaxError: can't assign to function call
T.temperature = 68, 'Fahrenheit'
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 19, in set_temperature
TypeError: can only concatenate tuple (not "float") to tuple
Upvotes: 1
Views: 894
Reputation: 612
I don't think getters and setters are necessary, nor pythonic... By using getters and setters you are making attributes of a class private to protect them from other codes. The pythonic way of providing this protection is actually by introducing the attributes publicly.
to design a class in a psuedo-java way you could do the following:
class temperature:
def __init__(self.temp):
self.__temp = temp
def get_temp(self):
return self.__temp
def set_temp(self, temp):
self.__temp = temp
and to access the data you would do the below
>>>temp1 = temperature(135)
>>>temp1.set_temp(14)
>>>temp1.get_temp()
14
however, a more pythonic way to design this class would be without the getter and setter and using a public attribute.
class temperature:
def __init__(self, temp):
self.temp = temp
Now you can just access the same attributes without having to use getters or setters
>>>temp1 = temperature(14)
>>>temp1.temp
14
Even though data is not necessarily encapsulated in this way ... it doesn't really need to be.
I realize that this doesn't address your concern with the three temperature scales but this can easily be accounted for by specifying the input temperature to a certain unit and then using conversion etc....
EDIT
On comment from @Carlo
The pythonic temperature class could be done below, assuming you specify an input temperature unit of kelvin, otherwise this class would need to be expanded to included farenheit and celsius input temperatures
class temperature():
def __init__(self, temp, unit):
self.temp = temp
self.unit = unit
if self.unit == 'K':
self.temp_k = self.temp
self.temp_c = self.temp_k + 273
self.temp_f = (self.temp_k + 273)*(9/5)+32
else:
raise TypeError("only kelvin accepted as input temperature")
if __name__ == '__main__':
temp1 = temperature(14, 'K')
temp2 = temperature(14, 'C') # will raise error
Accessing the temperature values for the temp1 object then simply becomes
>>> temp1.temp_k
14
>>> temp1.temp_c
287
>>> temp1.temp_f
548.6
Upvotes: 1