Mastering Classes and Objects in Python
Dive into Python's core object-oriented programming concepts with hands-on examples. Learn how classes and objects work, explore default methods, inheritance, and practical techniques to structure your code effectively.
Classes and Objects form the foundation of Object-Oriented Programming (OOP). Python relies on this concept, and understanding it is essential for writing structured, scalable, and maintainable code.
Think of classes as blueprints that group related data and functions/methods together which can be used and accessed by others. This is what we use to gain complete flexibility when coding in Python. They contain methods that can work together using concepts like HOF.
Objects is a term given to an instance of a class being used. They allow for parameters inside the class to store values or even perform functions. Think of assigning a normal variable to a function, here you would assign a normal variable to a class which then becomes an Object.
To give you a deeper analogy on Classes and Objects, everything we code in on Python is an Object. Your normal list() collection data type is an Object that can store information and perform functions on that data, like using List Comprehension.
A helpful way to conceptualize this is to think of a class as a blueprint, and an object as a specific instance built from that blueprint.
Creating a Class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Syntax
class ClassName:
# The __init__ method is called when we create a new object
# 'self' refers to the instance being created
def __init__(self, param1, param2):
self.param1 = param1 # Store values in the object
self.param2 = param2
# A method inside the class
def function1(self):
# Access the object's data using 'self.'
print(f"Param1 is {self.param1}, Param2 is {self.param2}")
## Using this Class:
# Creating an object of ClassName
obj1 = ClassName("Hello", 42)
# Calling a method on the object
obj1.function1()
Output:
Param1 is Hello, Param2 is 42
Hint: When creating classes it’s recommended to use camel case for the naming convention on each instance of a class which you’ll see on most of the examples I provide.
The self function is a very important concept to understand as it helps knowing what it does to create code. When I take this through ChatGPT to explain, this is what it says:
All methods inside a class must include
selfas their first parameter. This is becauseselfrefers to the current instance of the class. The main attributes of an object are typically defined inside the__init__method and stored on self. Other methods within the class can then access and use these attributes by referencingself.attribute_name. This makesselfthe mechanism that allows data to be shared across methods within the same object.
To use a more analogy-based approach to explain, self can be viewed as a parameter that stores data within an object using the correct class information. When we create an object, the values we pass in travel through the classes __init__ functions and get stored in the correct positional parameter variable. self is also used in all the methods inside the original class, as this is what allows the parameters and their values to travel between them also.
This is what allows multiple methods in a class to operate on the same underlying data—an essential feature of object-oriented design.
Here is an example of all of what I have mentioned:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Person:
def __init__(self, name, age): # Self parameter with other parameters
self.name = name
self.age = age
def greet(self): # including self in all other functions
print(f"Hello, my name is {self.name}, and I am {self.age} years old.") # Referring to each self attribute or parameter
def have_birthday(self):
self.age += 1
print(f"Happy birthday! I am now {self.age}.")
p1 = Person("Alice", 25)
p1.greet() # Hello, my name is Alice, and I am 25 years old.
p1.have_birthday() # Happy birthday! I am now 26.
p1.greet() # Hello, my name is Alice, and I am 26 years old.
Default Object Methods
Just as functions can define default parameters, classes can do the same through the __init__ method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Person:
def __init__(self, firstname='Sheikh', lastname='Hussain', age=250, country='UK', city='Manchester'):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.country = country
self.city = city
def person_info(self):
return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.'
p1 = Person()
print(p1.person_info())
# Sheikh Hussain is 250 years old. He lives in Manchester, UK.
p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
print(p2.person_info())
# John Doe is 30 years old. He lives in Noman city, Nomanland.
Taken from the course
Using Methods in Classes to Modify Values
This is a useful feature that allows us to manage and change information within an object we create. This logic illustrates how information can be stored and changed for each instance of an object.
In the example below, a method is used to append values to a list that belongs to the object itself:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Person:
def __init__(self, firstname, lastname, age, skills):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.skills = []
def add_skill(self, skill):
self.skills.append(skill)
def person_info(self):
return f'{self.firstname} {self.lastname} is {self.age} and has these skills:\n {self.skills}'
p1 = Person("Sheikh", "Hussain", 29, "HTML")
print(p1.person_info())
# Sheikh Hussain is 29 and has these skills:
# []
p1.add_skill("CSS")
print(p1.person_info())
# Sheikh Hussain is 29 and has these skills:
# ['CSS']
p1.add_skill("HTML")
print(p1.person_info())
# Sheikh Hussain is 29 and has these skills:
# ['CSS', 'HTML']
Think of the instance of the object you create as being a storage box with special features or functions that it can perform.
With each call of the object, you can retrieve different information that you have stored in it, and also have functions performed on the information.
Inheriting Class Values
The term inheritance in Classes refer to having one class and it’s methods transfer over to another class. The original class is regarded as parent and the subsidiaries as child.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Parent(): # Original Class
def __init__(self, firstname, lastname, occupation):
self.firstname = firstname
self.lastname = lastname
self.occupation = occupation
def person_info(self):
return f'{self.firstname} {self.lastname} and I am a {self.occupation}'
class Child(Parent): # Child class with 'Parent' as parameter
pass
parent = Parent("Katrina", "Kaif", "Wife")
child = Child("Sheikh", "Hussain", "Son") # Uses the same parameters/variables as Parent class.
print(parent.person_info())
# Katrina Kaif and I am a Wife
print(child.person_info())
# Sheikh Hussain and I am a Son
Inheriting Parameters
We can also have all the parameters of one class transferred to a new class. This is done using the super() function. This allows the child class to reuse the parents’ initialised logic for itself and then have new parameters exclusive to itself too.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Parent(): # initial class
def __init__(self, full_name, occupation, gender): # initial parameters
self.full_name = full_name.upper() # function in our parameter
self.occupation = occupation
self.gender = gender
def person_info(self):
gender = "He/Him" if self.gender == "Male" else "She/Her" # Creating a function for this variable
return f"I'm {self.full_name} and I'm a {self.occupation} my pronoun is {gender}"
# This call will return one type of object
class Child(Parent):
def __init__(self, full_name, occupation, gender, school):
super().__init__(full_name, occupation, gender) # Method used to initialise the same parameters while transferring them over
self.school = school # Adding a new parameter for this iteration
def person_info(self):
parent_info = super().person_info()
return f"{parent_info} and I attend {self.school}" # This class will return the same object with an addition to it.
p1 = Parent("harriet hilda", "Mother", "Female")
print(p1.person_info())
# I'm HARRIET HILDA and I'm a Mother my pronoun is She
p2 = Child("sheikh hussain", "Son", "Male", "Some School")
print(p2.person_info())
# I'm SHEIKH HUSSAIN and I'm a Son my pronoun is He and I attend Some School
Concluding Statement
After revisiting this topic, I would say that my understanding is a little better, but the application of these features will remain a little hazy until I’ve had some practical exercises with them.
I will most likely get AI to create some tasks for me to do, including the ones from the original course, to help me internalise this topic. This is what I like to do with most of the things I learn, as it gets me to learn at a steeper speed.
Programming logic emerges from refined creativity, which is developed through repetition and problem-solving. Repetition alone builds on familiarity but true intuition comes from knowing when and why to apply certain structures that I’ve learnt.
