In this section, we will learn about Object Oriented Programming in Python.
Object Oriented Programming in Python
The Object Oriented Programming (AKA OOP) is a method of designing a program by considering everything as an object! For example, let’s say you want to create a program that takes the information of cell phones (like the battery lifetime, model of that phone, attributes and functionalities that it has, etc.). Now one option to take such data would be to create a variable per each attribute of the phone and store the related information into that variable.
But in the world of OOP, the better method would be to design a specific object called Phone that represents the real world Phone and then store everything in there. Basically, everything in one place instead of using a gazillion variables!
Note: OOP is a big topic and learning it is a long process! So if get confused at this moment, just don’t worry, you’re in a good company. Keep reading the rest of this section and other sections that come after, multiple times and eventually it will click into place.
OOP Concepts: Classes and Objects in Python
In the world of OOP, there are two concepts:
– Python Class
Python has a set of built-in objects already and we can use them in our program. For example, List, Tuple, Dictionary, or basic objects like String, Integer, Float, etc. But the number of objects in Python is far limited than our needs. So, for example, if we want to have an object of type Phone or want to have an object of type Human etc. we need to build that ourselves because there’s no such thing as Phone or Human object in Python!
This is where Python Class comes in! At its core, a class is nothing but a blueprint, a plan, a design from which objects will be created.
For example, if you want to have a Phone object in your program, you need to first create a class called Phone and then put the necessary details about the object that would create from it.
Every detail (functionalities and attributes) that we need an object to have should be first designed in the body of a class. Then we can use that class and create the object we want.
-Python Object
On the other hand, objects are the built version of what we define in a class. Consider a House for example, the house itself is the built object which is the result of a bunch of blueprints and designs. Or a Car is an object that is built from a set of blueprints and plans.
Objects are the actual tools that we use in a program. Depending on how we design a class, the result object could have functions (AKA methods) and could be called in order to run different sorts of functionalities. An object can also store multiple types of data in its body and we can retrieve them at later times.
Alright, enough with theory, let’s dive into classes first and see how to create one.
Creating a Python Class (Define a Class in Python)
class ClassName: #body…
`class`: in order to create a class, we first start with the keyword `class`.
`ClassName`: Every class we create in Python has a name. We then use the name of a class to create objects from them at later times.
`#body…`: every indented line that comes after the class name (actually after the colon of a class name) is considered as part of the body of that class.
Before we get into the body of a class and see what we can put in the body of a class, first let’s create a bunch of class with an empty body:
Class in Python Example:
class Human: pass class Animal: pass class Car: pass
Here we have 3 classes with the names `Car`, `Animal`, and `Human`. The body of these classes is empty for now and hence we used the statement `pass` in order to stop Python execution engine to throw an error. (Check the pass statement section if you’re not familiar with this keyword)
What is a Method in Programming?
Within the body of a class, we can define functions! These functions then could be called using the objects that will be created from the class.
A function within a class is called method!
The way we create a method in the body of a class is pretty much the same as the way we create functions! Both have names, use `def` keyword, they can have parameters and accept arguments, etc.
But there’s one thing to remember when creating methods in classes: They need to have at least one parameter and that is called `self`. Basically, the first parameter of a method should be the keyword `self`.
In later sections, we will get into the details of the `self` keyword, but for now, just remember that the keyword `self` points to the object that invoked the target method! (We will get back to this in the rest of this section).
Example: adding methods to a class in python
class Human: def printName(self): print("I'm a Human") def sayHiToName(self, name): print(f"Hello {name}")
In this example, the `Human` class has two methods named `printName` and `sayHiToName`.
The `printName` method has only one parameter, and that is the keyword `self`. (Note that the self-keyword does not require us to pass an argument to the method! The self-keyword will be filled automatically by the python execution engine with the related data, which you’ll soon see what is the argument for this parameter).
The other method of the `Human` class is `sayHiToName`. This method has two parameters: `self` and `name`. (again, if a method needs multiple parameters, the first parameter should be the keyword `self`). Note that for this method, we only need to pass an argument for the `name` parameter if the method gets called in an operation. (The value of the `self` keyword will be passed automatically by the Python itself).
Constructor in Python: Python __init__ Method
Other than the ability to create a custom method for a Python class, Python also provided a set of built-in methods that could be used in classes as well.
One of these methods is called `__init__` (AKA the constructor method). The use of this method is necessary if we want the object that is going to be created from a class to have attributes as well.
Note: we will get into the attributes in just a second, but just remember that attributes are just simple variables within objects. We can pass values on them or retrieve their current values.
Also, when creating an object from a class, the `init` method will be called automatically and the attributes in its body will be initialized for the target object.
Example: python __init__ method
class Human: def __init__ (self, firstName, lastName): self.firstName = firstName self.lastName = lastName def printName(self): print(f"{self.firstName} {self.lastName}") human = Human("John","Doe") human.printName()
Output:
John Doe
Here, the `Human` class has the `__init__` method. The number of parameters we set for this method is optional and, depending on the design of the class, it can take as many parameters as necessary. (Note the first parameter must be the keyword `self`).
Note: the `init` method has two underscore before and after its name.
Now let’s see the body of the `__init__` method:
Here, we have two variables and each one of them has the keyword `self` attached to them.
The `self` keyword means the object that will be created from the target class. This keyword is basically a pointer to that object! So what happens within the body of the `__init__` method is that, we’re basically saying “Hey Python, create an attribute (variable) for the new object and name it `firstName` and assigned the value of the parameter `firstName` to this attribute. Also, create another attribute named `lastName` and assign the value of the parameter `lastName` to this attribute. “
So in short, the keyword `self` if it’s attached to a variable within the body of the `__init__` method, it means we’re creating attributes for the future objects of a class.
Now moving on to this statement:
human = Human("John","Doe")
This is a way of creating objects from a class. We will get into more details about how to create an object from a class, but in short, it’s like calling a function! Basically, we use the name of that class and put a pair of parentheses and then pass the same number of arguments equal to the number of parameters that the `__init__` method of the target class has.
In our example, the Human class has the `__init__` method with 2 parameters (the self-keyword is filled automatically) and so when calling this class to create an object from, we need to pass two arguments as well. These arguments then will be assigned to the parameters of the `__init__` method.
Note: after calling the Human class to create an object, the body of the `init` method will be executed and the two attributes `firstName` and `lastName` will be created for the new object.
Now let’s see this statement:
human.printName()
The `human` variable is now representing the new object.
First of all, if we want to call a method or an attribute of an object, we use the name of that object (human in this case) then a dot operator `.` and then the name of the target method or attribute (the printName() in this statement).
So basically, in this statement, we’re calling the `printName()` of the `human` object to be executed.
Now the body of this method will be executed. So let’s see what we have in the body of this method:
def printName(self): print(f"{self.firstName} {self.lastName}")
Note that in the body of this method we’re calling the `self.firstName` and `self.lastName`.
The keyword `self` is a pointer to the object that is calling this method (human in this example). So the `self.firstName` and `self.lastName` statements are basically saying we want the values that were assigned to the `firstName` and `lastName` attributes of the `human` object.
That’s why, after running this statement, we see the values `John Doe` on the output stream.
Example: creating attributes for a python class
Let’s create more attributes for the Human class:
class Human: def __init__ (self, firstName, lastName, age, email): self.firstName = firstName self.lastName = lastName self.age = age self.email = email def printName(self): print(f"{self.firstName} {self.lastName}") def printAge(self): print(f"{self.age}") def printEmail(self): print(f"{self.email}") def changeEmail(self, email): self.email = email human = Human("John","Doe", 50, "[email protected]") human.printName() human.printAge() human.printEmail() human.changeEmail("[email protected]") human.printEmail()
Output:
John Doe 50 [email protected] [email protected]
Here, the `init` method has two more parameters named `age` and `email`. So we need to pass arguments for these two parameters when creating an object from the Human class.
Let’s take a look at a new method in this class:
def changeEmail(self, email): self.email = email
This method takes one argument (for the email) and assigns that to the `self.email`.
What the statement within the body of this method is saying is that: call the object that invoked this method and get its `email` attribute, then assign the value of the `email` parameter as the new value for the `email` attribute. Basically, using this method, we can change the value of the `email` attribute of the `human` object.
Objects in Python (Instance of a Class)
As mentioned before, objects are the built version of classes. We use objects and not classes to invoke their methods in different sorts of operations.
Let’s see how can be create an object from a class.
Instance of a Class Syntax:
ClassName()
By default, and if there’s no `__init__` method in a class, all we need to do is to put a pair of parentheses on the right side of a class name. After that, a new object will be created from the target class and that can be assigned to a variable for later usage.
Note that when there’s no __init__ method or there’s one but with no parameter (except for the self-keyword) in a class, we only put an empty pair of parentheses on the right side of the target class name to create an object from it.
But if there is this method in the target class and it has a bunch of parameters as well, then when calling the Class to create an object from, we need to pass the same number of arguments as well to make the initialization to happen correctly.
Example: create an object in python
class Parent: def __init__ (self, firstName, lastName, age, email): self.firstName = firstName self.lastName = lastName self.age = age self.email = email parent = Parent("John","Doe",40, "[email protected]")
In this example, the Parent class has the `init` method (AKA constructor method) and also it hast 4 parameters as well. So we need to pass four arguments when calling the class to create an object from it.
How to Access Members of a Class in Python?
Here’s the syntax on how we can access the members of an object in Python:
objectName.memberName
`objectName`: this is the name of the object we want to access its members.
`.`: after the name of an object we use the dot `.` operator in order to access a member of an object.
`memberName`: this is the member of the target object we want to access. This member could be either the attribute of that object or a method.
Example: accessing members of a class in python
class Parent: def __init__ (self, firstName, lastName, age, email): self.firstName = firstName self.lastName = lastName self.age = age self.email = email parent = Parent("John","Doe",40, "[email protected]") print(parent.firstName) print(parent.lastName)
Output:
John Doe
As you can see, we used the `parent` object and the dot operator after that in order to access the `firstName` and `lastName` attributes.
Python Object: Creating attributes on the fly
Note that the attributes we put in the `init` method are not the only attributes of a class! We can still add more attributes after an object is created from a class!
To do this, first use the name of the target object that want to add a new attribute to it, then use the dot `.` operator and after that put the new attribute you want to add to the target object.
Note: right after the name of the new attribute comes the assignment operator `=` and on the right side of this operator, we need to put a value for that new attribute!
Example: creating new attributes for an object in python on the fly
class Parent: def __init__ (self, firstName, lastName, age, email): self.firstName = firstName self.lastName = lastName self.age = age self.email = email parent = Parent("John","Doe",40, "[email protected]") print(parent.firstName) print(parent.lastName) parent.city = "LA" print(parent.city)
Output:
John Doe LA
In this example, the `parent` object initially did not have the `city` attribute! So then we’ve added one for this object in this statement:
parent.city = "LA"
Note: when creating a new attribute for an object, only that object will have the new attribute! But the class itself and any other objects that were or will be created from the class won’t have the new attribute!
Difference between Class and Object
A class is just a plan, a blueprint that we use to create objects from. Although there are ways to use a class directly in Python but the typical application of a class is to be used as the blueprint for objects.
On the other hand, objects are the manufactured tools that are created based on the design set in the classes! Objects are the practical tools that can be executed, or get involve in different sorts of operations in a program.