Installation and Usage
Installation
Install the package (or add it to your requirements.txt
file):
$ pip install totemp
Or, in poetry environments:
$ poetry add totemp
Basic Usage and Representation
Note
The Base Class
is the one who makes the magic
happen in this package, for all the module detailed information go check every single class, its
methods, properties and other implementations there.
Thanks to Daniil Fajnberg we could finally solve the problems when trying to implement this base class.
When working with temperature scales representations and conversions, we often see a lack of “straight to the point” solutions beside of searching online for every single mathematical formula.
In that sense, everytime I (Edson) tried to represent those temperatures (using packages or implementing my own code) to automate any calculation/operation/representation, I was often stuck with little to none precise and simple way of doing it.
This package aims to bring the simple and straight to the point, but precise, Object Oriented experience of working with temperature scale data types.
For example, this:
1from totemp import Celsius, Fahrenheit, Kelvin, Delisle 2 3if __name__ == '__main__': 4 temps: list = [Celsius(12), Celsius(25), Celsius(50)] 5 print(temps[0]) 6 print(temps) 7 8 # Converts all Celsius objects using to_fahrenheit() method 9 temps = list(map(Celsius.to_fahrenheit, temps)) 10 print(temps[0]) 11 print(temps) 12 13 # Unpacks the temperature objects list 14 temp0, temp1, temp2 = temps 15 print(temp0.__repr__()) 16 print(temp0.__str__()) 17 print(temp0.value) 18 print(temp0.symbol) 19 20 # Converts to Kelvin and then rounds the value 21 temp1 = temp1.to_kelvin() 22 print(temp1) 23 print(temp1.rounded()) 24 25 # Converts to Delisle 26 temp2 = temp2.to_delisle().rounded() 27 print(type(temp2)) 28 print(type(temp2.value), f'-> {temp2.value}')
Outputs:
From line 5 and 10:
>>> '12 ºC' >>> '53.6 ºF' Calls to the __str__ method of the temperature object returns "`value`º `symbol`". That means that every call that need string representations of the temperature (such as print(), str() or `object`.__str__()) returns the value and its official symbol as a string.From line 6 and 11:
>>> [Celsius(12), Celsius(25), Celsius(50)] >>> [Fahrenheit(53.6), Fahrenheit(77.0), Fahrenheit(122.0)] And here we can see the "real representation" of the objects, shown by **__repr__** special method, that specifies its nature (which scale it is and it's value, and we can create a "new" object with those representations).From line 15, 16, 17 and 18:
>>> 'Fahrenheit(53.6)' # __repr__() >>> '53.6 ºF' # __str__() >>> 53.6 # `value` property >>> 'ºF' # Official `symbol` property Both special methods and the symbol property returns strings, but value is numeric, a float.From line 22 and 23:
>>> 298.15000000000003 K >>> 298 K Here we can see the calculation precision and the simplicity to make the result to be rounded, to become an aproximate int value.From line 27 and 28:
>>> <class 'totemp.temperature_types.Delisle'> >>> <class 'int'> -> 75 And now we have two type outputs, the first one is the type of the temp2 object and the other is the type of its value.
Arithmetic and comparison operations
Now we can look at the really interesting part of working with ToTemp temperature objects: perform operations between temperature data types and its iterations with other numeric data types.
Let’s go straight to it:
1import totemp as tp 2 3if __name__ == '__main__': 4 temp0, temp1 = tp.Celsius(0), tp.Fahrenheit(32) 5 6 # Celsius(0) > Fahrenheit(32) 7 if temp0 > temp1: 8 print(f'`temp0`->{temp0} is greater than `temp1`->{temp1}') 9 elif temp0 < temp1: 10 print(f'`temp0`->{temp0} is not greater than `temp1`->{temp1}') 11 else: 12 print('What...is...happening...?')
Outputs:
From line 12:
>>> What...is...happening...?
As you are probably thinking:
this doesn’t make sense… or it does?
When doing comparisons between temperature data types what are we trying to achieve? To check if the objects “are the same” or to check if the values equivalent? Or one is greater/lesser than another?
For example, comparing int(1) == float(1) would return True, and that’s exactly what’s happening in our temperature comparision.
The __gt__
special
method (and most of the other comparision and arithmetic special methods) checks
if the object being compared to the calling class is an Temperature Type or a
float/integer, if other is a Temperature, it attempts to convert the other object
to the calling class and then return the result of the evaluation (to be printed,
in our case).
Another example, with the same objects:
1import totemp as tp 2 3if __name__ == '__main__': 4 temp0, temp1 = tp.Celsius(0), tp.Fahrenheit(32) 5 6 print(f'temp0: {repr(temp0)}') 7 print(f'temp1: {repr(temp1.to_celsius())}') 8 9 print(temp0 > temp1) 10 11 print(temp0 < temp1) 12 13 print(temp0 == temp1) 14 15 print(temp0 != temp1) 16 17 print(temp0 >= temp1) 18 19 print(temp0 <= temp1)
Note
Using repr() just for better visualization
Outputs:
From lines 6 and 7:
>>> temp0: Celsius(0) >>> temp1: Celsius(0.0) The comparision/arithmetic implementation attempts to convert the value of other and then evaluate the expression. That meaning: `temp0` > `temp1.` is the same as `temp0` > `temp1.to_celsius()` The values being compared here are the equivalent values already converted! All that because of the calling class, `temp0` is an Celsius instance, so it will trigger a conversion of `other` to be compared with after.From lines 9 and 11:
>>> False >>> False The value of `temp0` isn't greater or lesser than `other` value, it is equal.From lines 13 and 15:
>>> True >>> False After the conversion of `temp1` (Celsius(0.0)) we could see that `temp1` has the same value, or better saying, has equivalent value to `temp0`.From lines 17 and 19:
>>> True >>> True And, as we saw in the previous outputs (from lines 13 and 15), comparisions that declare ">=" or "<=" would return True in that case, even though they aren't greater or lesser than each other, they are indeed equivalents.
After understanding how comparisions are done, we can now see how the arithmetic operations work.
Look at this:
1from totemp import Newton, Rankine 2 3if __name__ == '__main__': 4 temp0 = Newton(33) 5 temp1 = Rankine(671.67) 6 7 temp2 = temp0 + temp1 8 9 print('`temp2`:', temp2) 10 print('`temp2`:', repr(temp2)) 11 print('`temp2`:', temp2.value, temp2.symbol) 12 13 print((temp0 + temp1).rounded()) 14 print(repr((temp0 + temp1).rounded())) 15 16 print(temp2 + 12.55) 17 print((12 + temp2.rounded()))
Outputs:
From lines 9, 10 and 11:
>>> `temp2`: 65.99999999999999 ºN >>> `temp2`: Newton(65.99999999999999) >>> `temp2`: 65.99999999999999 ºN Just as the comparisions, most of the arithmetic operations that can be performed by the objects attempts to convert `other` to the same type as the calling class (in this case, to Newton).From line 13 and 14:
>>> 66 ºN >>> Newton(66) And, if needed, we can work with aproximate results too, we could aproximate just the values of `temp0` or `temp1`, none of them or even both before the operation actually happen. The thing is that every object can work as an aproximate or precise value of itself to perform more "embracing" operations, that the limits are mostly the way the developer/user is using it.From line 16 and 17:
>>> 78.54999999999998 ºN >>> 78 ºN Finally, as we can see, using ints and floats, even if the calling object isn't the temperature scale, it can return the right result.
Note
ToTemp classes can work with many built-in Python functions:
And temperature objects accept this kind of syntax:
>>> temp = Celsius(12)
>>> temp0 = -temp
>>> temp1 = -temp0
>>>
>>> print(temp0) # -12 ºC
>>> print(repr(temp0)) # Celsius(-12)
>>>
>>> print(temp1) # 12 ºC
>>> print(repr(temp1)) # Celsius(12)
So, with that shown, we can already assume that the other arithmetic operations do the same (attempts to convert other to the same type as the calling class, if don’t, it attempts to apply other to value directly).
Temperature Instance Conversions
Every temperature class has 7 conversions “from self to another” class which contains the converted value and one that returns a new instance of itself with the same value.
All “to_*” methods calls the convert_to() abstract method that was inhehited from the
Base Class
, this implies
that every class implements individual calculations for each of the following
conversions:
to_celsius() -> returns a
Celsius
object;to_fahrenheit() -> returns a
Fahrenheit
object;to_delisle() -> returns a
Delisle
object;to_kelvin() -> returns a
Kelvin
object;to_newton() -> returns a
Newton
object;to_rankine() -> returns a
Rankine
object;to_reaumur() -> returns a
Réaumur
object;to_romer() -> returns a
Rømer
object.
Just an example:
1import totemp as tp 2 3if __name__ == '__main__': 4 temp = tp.Fahrenheit(32) 5 6 print(temp.to_celsius()) 7 print(temp.to_fahrenheit()) 8 print(temp.to_delisle()) 9 print(temp.to_kelvin()) 10 print(temp.to_newton()) 11 print(temp.to_rankine()) 12 print(temp.to_reaumur()) 13 print(temp.to_romer())
Outputs:
From line 6 and 13:
>>> 0.0 ºC >>> 32 ºF >>> 150.0 ºDe >>> 273.15 K >>> 0.0 ºN >>> 491.67 ºR >>> 0.0 ºRé >>> 7.5 ºRø
Now using convert_to()
:
1from totemp import * 2 3if __name__ == '__main__': 4 temp = tp.Fahrenheit(32) 5 6 print(temp.convert_to(Celsius)) 7 print(temp.convert_to(Fahrenheit)) 8 print(temp.convert_to(Delisle)) 9 print(temp.convert_to(Kelvin)) 10 print(temp.convert_to(Newton)) 11 print(temp.convert_to(Rankine)) 12 print(temp.convert_to(Reaumur)) 13 print(temp.convert_to(Romer))
Outputs:
From line 6 and 13:
>>> 0.0 ºC >>> 32 ºF >>> 150.0 ºDe >>> 273.15 K >>> 0.0 ºN >>> 491.67 ºR >>> 0.0 ºRé >>> 7.5 ºRø
—
And that’s an overall vision of the package and what it can do.
Now, you can go to the Module section.