avatarKurt F.

Summary

The provided content discusses the concept of composition in Python through five detailed case studies, illustrating its benefits and practical applications in creating flexible and reusable code structures.

Abstract

The article "The Best Way to Understand Composition in Python: 5 Case Studies and Solution" delves into the importance of composition as a technique for establishing relationships between classes in object-oriented programming. It emphasizes that composition allows for more dynamic and maintainable code by enabling the combination of objects from different classes without relying on inheritance. The author presents five comprehensive examples to demonstrate how composition can be applied in various scenarios, such as calculating annual salary, organizing materials in a freezer, categorizing zoo animals, managing personal and address information, and counting clothing items made of cotton. Each case study provides Python code snippets that showcase the implementation of composition, reinforcing the concept's utility in real-world programming tasks. The article concludes by highlighting the practical methodology of using composition in Python to enhance coding efficiency and encourage deeper learning.

Opinions

  • The author believes that composition is a superior alternative to inheritance for creating complex code relationships in Python.
  • It is suggested that composition leads to more flexible and maintainable code structures, as it allows for the addition of new features without altering existing code.
  • The author values the reusability of code, which is facilitated by the use of composition, as it enables the use of objects' functionality without duplicating code.
  • The article conveys that understanding compositions is crucial for effective object-oriented programming, as it promotes a clearer decision-making process regarding class definitions and their interactions.
  • The author's approach to teaching composition through practical examples and code implementation indicates a preference for hands-on learning and the importance of applying theoretical concepts to concrete situations.

The Best Way to Understand Composition in Python: 5 Case Studies and Solution

Understanding and applying compositions in a short time

Photo by Juan Carlos Becerra on Unsplash

Introduction

Compositions; It is a programming technique used when establishing relationships between classes and objects. Understanding compositions is important in object-oriented programming. Compositions can be a good idea in Python and software language to make a particular structure dynamic. Because in this way, we fill the place of complex code blocks with more compact material.

Why Composition?

Through the compositions, we actually state the relationship between the two classes. And in this way, the code can be reused. This has a common similarity with the concept of inheritance. As a result, we obtain more complex structures by combining objects between different types.

What we need to understand with quality; is our ability to reach a clear decision thanks to the conformity with the definitions made about a class member. Values and methods are created about the breed, such as an apple is a fruit and a fawn being an animal. And the attributes and methods created for these main classes are exactly applied to the lower classes. After the application, the results are expected not to conflict with the upper class. Of course, this will save you from code repetitions.

In the composition, the code is reused by adding other objects to objects instead of inheriting properties, created methods between classes. And indeed, classes created by composition are more flexible than the structure created by heritage. This is because adding new features without changing the existing code structure is more effective.

So we can highlight three main points:

  • One of the classes that exist in the composition is created from one (or more) examples of the others.
  • We can also function in some aspects of a class without using all the properties of another class.
  • It is possible to reuse code by adding objects to different objects.

Composit and Components Class

As we mentioned above, it becomes possible to encode in a complex relational structure with compositions. This happens when the Composite class can contain another Component class object.

Component Indicates the number of instances or valid range the Composite class will contain.

Now, we proceed to consolidate our knowledge through examples.

Example-1: Creating an annual salary between salary and staff classes

A workplace can determine how much an employee has to pay by defining the Salary class. However, this can also be expressed well with different parameters as an employee’s income. For example, for an employee with a monthly salary of 2600 €, the annual sum can be determined with a 12-month payment. We can add an additional parameter to this, like the annual bonuses. Then let’s run a function from the Salary class in the employee class and view the Total salary:

class Salary:
    def __init__(self, monthly_income):
        self.monthly_income = monthly_income
 
    def get_total(self):
        return (self.monthly_income*12)
 
 
class Employee:
    def __init__(self, monthly_income, bonus):
        self.monthly_income = monthly_income
        self.bonus = bonus
        self.obj_salary = Salary(self.monthly_income)
 
    def annual_salary(self):
        return "Total: " + str(self.obj_salary.get_total() + self.bonus) + ' €' 
 
 
obj_emp = Employee(2600, 500)
print(obj_emp.annual_salary())
output:
Total: 31700

Example-2: Composing by putting different substances in a material

For this example, we need a Freezer class. We will fill different materials into our main class and then try to view them in an empty list, which we will first mark as blank. We will have only one class, but in this class, the functions of storing and displaying the material will solve our problem. Then:

class Freezer(object):
    def __init__(self):
        self._container = []
    def store(self, obj):
        self._container.append(obj)
    def stuff(self):
        return self._container[:]
deepfreezer = Freezer()
deepfreezer.store('fish')
deepfreezer.store('pea')
deepfreezer.store('meat')
deepfreezer.stuff()
output:
['fish', 'pea', 'meat']

Example-3: Composing types in the zoo

Our aim here is to make a composition process that will give how many zoo animal species are in the category of birds. For this, we will first create the animal class. We will then designate the two different bird species (Falcon and Parrots) into the bird category. And finally, we will print how many different bird species exist within the zoo class according to the data of the 3 separate classes we have identified above. According to this:

class Animal:
    name = ""
    category = ""
    
    def __init__(self, name):
        self.name = name
    
    def set_category(self, category):
        self.category = category
class Falcon(Animal):
        category = "birds"
class Parrots(Animal):
    category = "birds"
class Zoo:
    def __init__(self):
        self.current_animals = {}
    
    def add_animal(self, animal):
        self.current_animals[animal.name] = animal.category
    
    def total_of_category(self, category):
        result = 0
        for animal in self.current_animals.values():
            if animal == category:
                result += 1
        return result
zoo = Zoo()
falcon = Falcon("Falcon") #create an instance of the Falcon class
parrots = Parrots("Parrots") #create an instance of the Parrots class
zoo.add_animal(falcon)
zoo.add_animal(parrots)
print(zoo.total_of_category("birds")) #how many zoo animal types in the birds category

If you examine the code well, you will notice that we return the current_animals.values () function for category count. Here is the part we are interested in because we want to see types rather than the number of birds or animals.

Example-4: Composing personnel and address classes

Composing this structure will allow for deeper learning. In our example, a software firm wants to record basic information about job applications. Information such as name-surname-coding history and address of the person that is important for them here. And for this, we want to create a print out that we can compose by calling up common functions between the person class and the Address class as two separate classes.

We want the sub-functions to include the display function basically in the person class. So let’s do:

class Personal:
    def __init__(self,name,surname, programming_language, experience):
        self.name=name
        self.surname=surname
        self.programming_language=programming_language
        self.experience=experience
        self.address=None
    
    def View(self):
        print(f"Personal Name & Surname: {self.name} {self.surname}")
        print(f"Experience period: {self.experience} year")
        print()
        if self.address:
            print("Address: ")
            print(self.address)
        print()
        print("Programming Languages Used: ")
        data_type=type(self.programming_language)
        if data_type is str:
            print("  - ", self.programming_language)
        elif data_type is tuple or list:
            for language in self.programming_language:
                print("  - ", language)
        else:
            print("Error!")
        print("")
        print("-------------------------")
        print("")
class Address:
    def __init__(self, ad, district,city,land):
        self.ad=ad
        self.district=district
        self.city=city
        self.land=land
    def __str__(self):
        details=[self.ad]
        if self.land:
            details.append(self.land)
            details.append(f"{self.district}/{self.city}")
        return '\n'.join(details)
personal1 = Personal("Markus","Faber",("Python","PHP","Javascript","Java"), 18)
personal1.address=Address('Brienner St. 0123', 'Maxvorstadt','Munich',"GERMANY")
personal2 = Personal("Arim","Khandakar",("NodeJS","ReactJS"), 6)
personal2.address =Address('Rd No 456','Kalachandpur','DHAKA',"BANGLADESH")
personal3 = Personal("Julia","Gage",("Javascript","CSS"), 4)
personal1.View()
personal2.View()
personal3.View()
output:
Personal Name & Surname: Markus Faber
Experience period: 18 year
Address: 
Brienner St. 0123
GERMANY
Maxvorstadt/Munich
Programming Languages Used: 
  -  Python
  -  PHP
  -  Javascript
  -  Java
-------------------------
Personal Name & Surname: Arim Khandakar
Experience period: 6 year
Address: 
Rd No 456
BANGLADESH
Kalachandpur/DHAKA
Programming Languages Used: 
  -  NodeJS
  -  ReactJS
-------------------------
Personal Name & Surname: Julia Gage
Experience period: 4 year
Programming Languages Used: 
  -  Javascript
  -  CSS
-------------------------

We created the __str__ method to make the address data look stylish. In the personal class, we first equated the address to ‘None’ and created it as a flexible variable. In this way, we made sure that the person who did not enter an address did not receive any errors.

Example-5: Composing clothes made of cotton materials by counting

Our last example is similar to the example of the products we placed in the freezer. This time, we will not look at the deep freezer, but maybe at our wardrobe. But here we want to count different types of clothing of the same material: Cotton shirts and trousers. This will also be an example of storage.

First of all, we will create a class that determines the name, material, and quantity of the product during the stocking phase. Each list will be set empty first. We will then define the functions in this class. The function of adding a product will then be a function of counting by the material. Then we will make variable assignments in the Shirt and Pants classes. And we will try to display products made from ‘Cotton’. Let’s do it:

class Clothing:
    stock={ 'name': [],'material' :[], 'amount':[]}
    def __init__(self,name):
        material = ""
        self.name = name
    
    def add_item(self, name, material, amount):
        Clothing.stock['name'].append(self.name)
        Clothing.stock['material'].append(self.material)
        Clothing.stock['amount'].append(amount)
    
    def Stock_by_Material(self, material):
        count=0
        n=0
        for item in Clothing.stock['material']:
            if item == material:
                count += Clothing.stock['amount'][n]
                n+=1
        return count
class Shirt(Clothing):
    material="Cotton"
class Pants(Clothing):
    material="Cotton"
formal = Shirt("Formal")
dress_pants = Pants("Dresspants")
formal.add_item(formal.name, formal.material, 13)
dress_pants.add_item(dress_pants.name, dress_pants.material, 7)
current_stock = polo.Stock_by_Material("Cotton")
print(current_stock)
output:
20

Conclusion

In Python, we tried to understand the methodology of Composition and gain practicality in practice. We have learned how to use the empty dictionaries and lists in the desired formats thanks to the attributes and variables assigned in sub-types of our initially empty classes. In this way, I hope with greater courage, an article has been formulated that will help you encode interclass composition.

Thank you for reading!

Programming
Software Development
Python
Data Science
Composition
Recommended from ReadMedium