Make Your Python Code Fluent

Make Your Python Code Fluent

Originally posted on towardsdatascience.

With Function and Operator Overloading

Overloading in Python allows us to define functions and operators that behave in different ways depending on parameters or operands used.

Operator Overloading

As an example, we can use “+” operator to do arithmetic calculations on numerical values while the same “+” operator concatenates two strings when strings operands used. This is called operator overloading and it allows us to use the same operator on different object types to perform similar tasks.

As shown below, we can overload “+” operator to use it with our custom-made object types as well.

# No overloading, task is performed by 'add' method
cost1 = Cost(10)
cost2 = Cost(24)
cost_total = cost1.add(cost2)# '+' operator is overloaded to work with 'Cost' type of objects
cost1 = Cost(10)
cost2 = Cost(24)
cost_total = cost1 + cost2

The second code block above is easy to read and understand compared to the first one. This is how overloading makes our code fluent and clean.

Function Overloading

Although Python does not support function overloading by default, there are ways of implementing it with some tricks.

Let’s consider that we want to create a function to calculate the area of a triangle. The user can provide;

  • Base and height of the triangle or,
  • Length of three sides of the triangle

We need to define two different functions to handle the task if we don’t consider overloading.

Instead of having different function definitions for the same task, we can write only one function and overload it to increase code consistency and readability.

#---------------------
# No overloading, task is performed by two similar functions
#---------------------
def triangle_area_base_height(base, height):
....
def triangle_area_three_sides(a_side, b_side, c_side):
....area1 = triangle_area_base_height (10,14)
area2 = triangle_area_three_sides (10, 12,8)
#---------------------
# Function overloading
#---------------------
from multipledispatch import dispatch@dispatch(int,int)
def triangle_area(base, heigth):
.....@dispatch(int,int,int)
def triangle_area(a_side, b_side, c_side):
.....area1 = triangle_area (10,14)
area2 = triangle_area (10,12,8)

Overloading Operators

When we use an operator, a special function associated with that operator is invoked. As an example, when we use + operator, the special method of __add__ is invoked. To overload + operator, we need to extend the functionality of __add__ method in a class structure.

# Addition of 2D point coordinates with
# + operator overloading
class Point2D:
def __init__(self, x, y):
self.x = x
self.y = y# adding two points
def__add__(self, other):
return self.x + other.x, self.y + other.ydef __str__(self):
return self.x, self.ypoint1 = Point2D(5, 4)
point2 = Point2D(6, 1)
point3 = point1 + point2print(point3)Output:
(11, 5)

Instead of defining an additional function to add Point2d objects, we can overload + operator to have more fluent and easy to read code.

You can overload all operators including assignment, comparison and binary ones by modifying the associated special methods in a class structure.

Overloading Built-in Functions

We can also overload built-in Python functions to modify their default actions. Consider the len() built-in function which returns the number of objects in a sequence or collection. To use it with our custom-made object type, we need to implement overloading.

To overload len(), we need to extend the functionality of __len__ method in a class structure.

Let’s see below how we can do it in Python:

class Names:def __init__(self, name, country):
self.name = list(name)
self.country = countrydef __len__(self):
return len(self.name)obj1 = Names(['Amy', 'Harper', 'James'], 'UK')
print(len(obj1))Output:
3

You can similarly overload all built-in functions.

Image for post
Photo by Chundy Tanz on Unsplash

Overloading User-Defined Functions

Python does not support function overloading by default. But we can use multiple dispatch library to handle overloading.

After importing multipledispatch, what we need to do is to decorate our functions with @dispatch() decorator.

import math
from multipledispatch import dispatch
@dispatch(int,int)
def triangle_area(base, height):
return (base*height)/2@dispatch(int,int,int)
def triangle_area(a_side, b_side, c_side):
s = (a_side + b_side + c_side) / 2
return math.sqrt(s * (s-a_side) * (s-b_side) * (s-c_side))area1 = triangle_area (10,14)
area2 = triangle_area (5,5,5)print("Area1: {}".format(area1))
print("Area2: {}".format(area2))Output:
Area1: 70.0
Area2: 10.825317547305483

Key Takeaways

  • Overloading in Python allows us to define functions and operators that behave in different ways depending on parameters or operands used.
  • Operator overloading allows us to use the same operator on different object types to perform similar tasks.
  • Instead of having different function definitions for the same task, we can write only one function and overload it to increase code consistency and readability.

Conclusion

In this post, I explained the basics of overloading in Python.

The code in this post is available in my GitHub repository.

I hope you found this post useful.

Thank you for reading!

Source: towardsdatascience