Functions have there use cases, classes have theirs. One is able to act upon random objects (of suitable type) while the other is able to act only upon instances of the class (custom objects).
>>> def sss_triangle_area(*sides):
'''
Area of S-S-S triangle using Heron's Formula
'''
if len([*sides]) != 3: raise ValueError
a, b, c = sides
try:
(a + b + c) / 0
except ZeroDivisionError:
pass
if a + b <= c or b + c <= a or a + c <= b: raise ValueError
s = (a + b + c) / 2
return (s * (s - a) * (s - b) * (s - c)) ** 0.5
>>> sss_triangle_area(3,4,5)
6.0
>>> sss_triangle_area(1,4,5)
Traceback (most recent call last):
File "<pyshell#228>", line 1, in <module>
sss_triangle_area(1,4,5)
File "<pyshell#226>", line 11, in sss_triangle_area
if a + b <= c or b + c <= a or a + c <= b: raise ValueError
ValueError
>>> sss_triangle_area('3','4','5')
Traceback (most recent call last):
File "<pyshell#229>", line 1, in <module>
sss_triangle_area('3','4','5')
File "<pyshell#226>", line 8, in sss_triangle_area
(a + b + c) / 0
TypeError: unsupported operand type(s) for /: 'str' and 'int'
>>>
Above we’ve written a function that resides in the global namespace. It contains all the validation it needs to ensure the sides are values and that they indeed represent a triangle.
That’s just one method for computing area. There are SAS, ASA, and AAA methods as well. That means having four functions in the namespace that have no real connection to each other. By writing a class definition we can include all the methods within the one definition and have them all apply to valid object instances.
With a class we have only to define an instance once, and after that all methods are accessible without having to give arguments every time like we would have to do with the four functions mentioned above.
Think on this for a time, while I drum up an example of a class to create triangle instances.