Design Object-Oriented Code in Python

8694-10.jpg

Python developers often argue about which programming approach is better: procedural or object-oriented. Of course, this is largely a philosophical question, but for any task, you can determine whether to use classes, inheritance, polymorphism, or encapsulation. Let's see how this happens in Python.

What is Python

As described in the Executive Summary on the Python website: “Python is an interpreted, object-oriented, high-level programming language with dynamic semantics. Its high-level built-in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting or glue language to connect existing components together. Python's simple, easy-to-learn syntax emphasizes readability and therefore reduces the cost of program maintenance. Python supports modules and packages, which encourages program modularity and code reuse. The Python interpreter and the extensive standard library are available in source or binary form without charge for all major platforms, and can be freely distributed.

This means that Python was originally designed as an object-oriented language. This approach greatly improved work with classes and OOP; it is unlike other programming languages, where OOP is developed on top of a standard procedural or structural programming model.

What is Object-Oriented Programming

An abstraction in object-oriented programming is giving the object characteristics that distinguish it from all objects, clearly defining its conceptual boundaries. The main idea is to separate the way of using composite data objects from the details of their implementation. It can be done in the form of simpler objects, just as a functional abstraction separates the way of using a function and the details of its implementation in terms of more primitive functions. The data is processed at a high level by using low-level functions.

Encapsulation is a property of the programming language that allows the user not to think about the complexity of the implementation of the used software component. It allows users to interact with it through the provided interface, i.e. public methods and members, and to combine and protect the data vital to the component. In this case, the user is provided only with a specification, i.e. object interface.

Inheritance is one of the four most important mechanisms of object-oriented programming, along with encapsulation, polymorphism, and abstraction, and it allows you to describe a new class based on an existing parent, while the properties and functionality of the parent class are borrowed by the new class.

Polymorphism is the ability of objects with the same specification to have different implementations. Briefly, the meaning of polymorphism can be expressed as "one interface, many implementations". 

Why Use OOP in Python

The best explanation of why you need to use OOP in Python, IMHO, was provided by the respected Jim Dennis, in an article “Python from an Ops perspective”.

Here is a quote from this wonderful explanation. “When is it better to use Python’s object-oriented programming (OOP) support over simple procedural or imperative programming? One answer, of course, is when your requirements become sufficiently complex that simple imperative designs become difficult to implement and maintain. (Actually, a better answer would be: when you anticipate that they will become onerous, so you can shift towards an object-oriented design before you need to.)

OOP was developed as a means to manage complexity. Instead of having complex data structures and a plethora of functions to operate on each, OOP allows the programmer to couple data structure and related functionality (behavior, methods for accessing and manipulating the data) into objects. This entails describing the objects in terms of their class and generally also means supporting hierarchies of related classes (inheritance) and managing complex objects containing references to other objects (composition).

For an in-depth study, you can read another great article.

Python

Best Practices with Object-Oriented Python

Consider an example of solving a quadratic equation with classes in Python. This example will be easy for beginners to understand in Python and will show that programming with an object-oriented approach in Python can be mastered quite easily.

Web Solutions

While we focus on creating one class, it cannot fully reveal all the possibilities of OOP in Python. But for beginners, this class shows that you don’t need to be afraid to use classes and this has its advantages.

This example has a constructor with a, b, c coefficients for quadratic equations and methods for the calculation of discriminant and roots of the equation. This code is created to keep it as simple as possible, but effective.

import math
 
class QuadraticEquation:
   """Class for solving quadratic equation."""
 
   def __init__(self, a, b, c):
       """
       Parameters
       ----------
       a : double
           The a coefficient
       b : double
           The b coefficient
       c : int, optional
           The c coefficient
       """
       self.a = a
       self.b = b
       self.c = c
  
   def discriminant(self):
       return ((self.b)**2) - (4 * self.a * self.c)
 
   def discsqrta(self):
       return math.sqrt(self.discriminant()) / (2 * self.a)
 
   def x1(self):
       """ Return first root of quadratic equation
 
       Returns
       -------
       double
           a first root of quadratic equation if any
       """
       if self.discriminant() < 0:
           return None
       else:
           return -self.b / (2 * self.a) + self.discsqrta()
 
   def x2(self):
       """ Return second root of quadratic equation
 
       Returns
       -------
       double
           a second root of quadratic equation if any
       """
       if self.discriminant() < 0:
           return None
       else:
           return -self.b / (2 * self.a)- self.discsqrta()

Now let's write a unit testing class for this task.

import unittest
 
a = QuadraticEquation(4, 2, -2)
print (a.x1(), a.x2())
 
class TestRoots(unittest.TestCase):
 
   def test_roots(self):
       self.assertEqual(a.x1(), 0.5)
       self.assertEqual(a.x2(), -1.0)
       self.assertEqual(a.discriminant(), 36)
      
 
unittest.main(argv=[''], verbosity=2, exit=False)

Let’s run it for execution:

test_roots (__main__.TestRoots) ... 0.5 -1.0
ok

----------------------------------------------------------------------
Ran 1 test in 0.002s

OK
<unittest.main.TestProgram at 0x7fbc2be6eef0>
Code language: CSS (css)

Both tests passed, very well.

Consider some of the key benefits of object-oriented programming:

  • Object-oriented programming involves reusing code and functionality. A computer program written in the form of objects and classes can be used again in other projects without repeating the code
  • Using a modular approach in object-oriented programming allows you to get readable and flexible code
  • In object-oriented programming, each class has a specific task. If an error occurs in one part of the code, you can fix it locally, without having to intervene in other parts of the code
  • Data encapsulation introduces an additional level of security into the program being developed using an object-oriented approach

Although object-oriented programming has several advantages, it also contains certain disadvantages, some of which are listed below:

  • To create objects, you must have a detailed understanding of the software being developed.
  • Not every aspect of the software is best implemented as an object. For beginners, it can be hard to draw a line in the middle ground.
  • As you introduce more and more classes into the code, the size and complexity of the program grow exponentially.

Here is one recommended Python course, useful for both beginners and experienced Python programmers.

Conclusion

In conclusion, let’s note that the experts from Svitla Systems highly recommend writing object-oriented code and actively use this approach. It is imperative to read the articles listed above, you will not regret the time spent and appreciate the advantages of the approach of using classes and the main paradigms of the object-oriented approach.

Svitla Systems will always recommend using the latest technology exactly where it is needed. Our project development concept is always focused on maximum execution quality and a cost-effective solution. Our company, Svitla Systems, has a large community of Python developers in the field of web development, and in the areas of data science, computer vision, DevOps, and so on (since a lot of tasks can be solved with the help of Python and the corresponding frameworks). Remember that the simplest solutions are the most reliable; use the KISS (Keep it simple, stupid) principle where necessary.

We wish you a successful use of object-oriented programming in Python and other programming languages.