Temperature Converter: °C to K

What it does

• Converts melting point and boiling point from degrees celsius to kelvin
• These are in a dict which is in a tuple as no changes should be made to it
• No user input

Purpose

Learning exercise to understand classes and OOP

What I need help with

• Is this how you do classes?
• Is this correct OOP?
• Suggest any improvements?

Code:

from typing import Dict

class ConvertToKelvin:
def __init__(self, substance: str, data: Dict[str, int]):
self.substance = substance
self.data = data

def to_kelvin(self, celsius: int) -> int:
return celsius + 273

def __str__(self):
sub = self.substance
mp = self.to_kelvin(self.data["mp"])
bp = self.to_kelvin(self.data["bp"])
return f'{sub}:\n mp: {mp}K\n bp: {bp}K\n'

data = (
ConvertToKelvin(
'water',
{
'bp': 0,
'mp': 100
}
),
ConvertToKelvin(
'imaginary',
{
'bp': 30,
'mp': 120
}
),
)

print('\n'.join(str(i) for i in data))

Output:

water:
mp: 373K
bp: 273K

imaginary:
mp: 393K
bp: 303K
• to_kelvin(self, celsius: int) seems more like a general utility function rather than a method related to or acting on ConvertToKelvin. If this was more integrated, I might expect ConvertToKelvin to have a property celsius similar to substance and that one would get the converted value via to_kelvin(self). Jun 14 '21 at 17:08
• That’s right, it’s because I’m so used to just using functions to do things having a hard time grasping OOP as for some things I just don’t get how they can be used as a ‘blueprint’ Jun 14 '21 at 19:21
• Is bp = "boiling point" and mp = "melting point"? Do you have those switched? Jun 15 '21 at 0:04
• Yeah… err thanks :) Jun 15 '21 at 19:46

• ConvertToKelvin sounds like a method (it's a verb), when you actually need a noun
• You're actually capturing two different things - a temperature, and a substance
• The figure of 273 is incorrect and should actually be 273.15
• Avoid dictionaries for the purposes of internal state representation
• These are simple enough that a dataclass is well-suited, and should be immutable given the nature of your data hence why frozen is set
• Your use of int should probably be float instead. Temperatures are not discrete values.

Suggested

from dataclasses import dataclass

@dataclass(frozen=True)
class Temperature:
celsius: float

@property
def kelvin(self) -> float:
return self.celsius + 273.15

def __str__(self):
return f'{self.kelvin} K'

@dataclass(frozen=True)
class Substance:
name: str
melt: Temperature
boil: Temperature

def __str__(self):
return (
f'{self.name}:\n'
f' melt: {self.melt}\n'
f' boil: {self.boil}\n'
)

substances = (
Substance(
'water',
Temperature(celsius=0),
Temperature(celsius=100),
),
Substance(
'2-methylobenzenol (o-cresol)',
Temperature(celsius=30),
Temperature(celsius=191),
),
)

print('\n'.join(str(i) for i in substances))
• Thank you, I used your last answer as a base to get familiar with classes and also to understand what you done which was impressive as all the guides deal only with user input like setting a value manually. There’s just one thing I don’t get how would you implement this as a ‘blueprint’? Thanks for correcting me on the precise value of converting to K, since you seem to be a man who loves precision, I think it’s just K Rather than degrees K :) but it was a good point for using a float thanks again Jun 14 '21 at 19:19
• You're right; I never knew that! Per Wikipedia, Unlike the degree Fahrenheit and degree Celsius, the kelvin is not referred to or written as a degree. Jun 14 '21 at 19:53
• As for a "blueprint", there's a large collection of strategies for class representation in Python and which to use varies widely based on circumstance. Jun 14 '21 at 19:58
• I’m just curious how you know some of the stuff you come out with, can’t find any guides that show the cool things you’ve shown me Jun 14 '21 at 21:11
• Stop using dicts. Don't name a class Calculate - that's the name of a method (verb), not a class (noun) Jun 18 '21 at 0:07

Very nice question and great use of types! Let us step through your questions one at a time

Is this how you do classes

I would argue no, but let us take a step back and look at how brilliant classifies as a class:

In object-oriented programming, a class is a blueprint for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementations of behavior (member functions or methods).

The user-defined objects are created using the class keyword. The class is a blueprint that defines a nature of a future object. An instance is a specific object created from a particular class. Classes are used to create and manage new objects and support inheritance—a key ingredient in object-oriented programming and a mechanism of reusing code. So my problem with your class is that it is really not describing an object is it? It is really describing a function (please convert my temperature from X to Y).

Is this correct OOP?

As mentioned above I would not use classes in the way you are using them from a design standpoint. However, your implementation seems good. You are using types and overall it looks good.

Suggest any improvements?

Ok. So if ConvertToKelvin does not describe an object, what would? Something that comes to my mind is Kelvin, Celsius or even Temperature

Something like ought to do the trick

class Celsius:
absolute_zero = -273.15

def __init__(self, temperature=0):
self.temperature = temperature

def to_fahrenheit(self):
return (self.temperature * 1.8) + 32

def to_kelvin(self):
return self.temperature - self.absolute_zero

@property
def temperature(self):
return self._temperature_C

@temperature.setter
def temperature(self, value):
if value < self.absolute_zero:
raise ValueError(f"Temperature below {self.absolute_zero} is not possible")
self._temperature_C = value
self._temperature_F = self.to_fahrenheit()
self._temperature_K = self.to_kelvin()

def __str__(self):
return f"""Temperature:
Celcius: {self._temperature_C}
Fahrenheit: {self._temperature_F}
Kelvin: {self._temperature_K}
"""

The @property lets us even raise an error if the temperature is not valid. As can be seen by running something like

outside = Celsius(50)
print(outside)
outside.temperature = 25
print(outside)
# outside.temperature = -300
# print(outside)
• You’re right because all I really know are functions, I just thought how the hell can this be a blueprint for something but I seen some people using classes where I would just use functions, thanks a lot for the tips :) I’m starting to get it more now Jun 14 '21 at 19:14