Imagine you want to build a house. You need a blueprint first, right?
- Class: The blueprint is like a class in Python. It’s the detailed plan that tells you how to build your house – the number of rooms, the layout, where the windows go, and so on.
- Object: The actual house you build is the object. It’s the real thing, built from the blueprint, where you can actually live.
Another way to approach this is to think of a class as a recipe; an object is the cake you bake from that recipe. You can’t eat the recipe, but you can enjoy many different cakes made from the recipe!
Table of Contents | |
What Is a Class in Python?
Python class is a fundamental concept that allows you to create custom objects with properties and behaviors. Think of a class as a blueprint or a template for creating objects with specific characteristics and behaviors. Class in Python provides a way to organize and structure your code, making it easier to manage and reuse. By defining classes in Python, you can encapsulate data and functions together, creating more modular and efficient programs.
Creating a Python Class
To define a class, we use the keyword class followed by the class name in CamelCase. Within the class, we define its attributes, which describe its state. The following shows the basic syntax for creating a class named Car:
Python Class Example
class Car:
pass
Explanation
- The
class
keyword defines a new class. - The name of the class is
Car
. - Colon (
:
) indicates the start of the class block (body). - The
pass
statement indicates that the class body is empty for now. Later, you can fill it in with the specific code (attributes and methods) defining different car types.
Everything in a class is indented, just like the code within a function, if statement, for loop, or any other block of code.
The __init__() Method of Python Class (Constructor)
When you create a new object from a class in Python, the __init__() method is automatically called. This special method has two leading and two trailing underscores, a convention that helps prevent Python’s default method names from conflicting with your method names. Use two underscores on each side of __init__(). If you use just one on each side, the method won’t be called automatically when you use your class, which can result in errors that are difficult to identify.
Example
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
Explanation
__init__
Method (Constructor)
- Special Name: The
__init__
name is significant. The double underscores (__) on either side indicate that it’s a special method in Python. - self Argument: The first argument of the
__init__
method is alwaysself
. This is a reference to the object on which the method is being called. In the case of the__init__
method, this reference refers to the newly createdCar
. The__init__
method uses self-reference to find this newly created object and set up each of the data attributes for this object. - Additional Arguments: You can add more arguments after
self
to pass in values specific to the current object. These values are then used to initialize the object’s attributes. Here make, model, and year are the attributes (properties) of the car. The constructor stores these values within the object.
The three variables (make, model, and year) defined in the body of the __init__() method have the prefix self. Any variable prefixed with self is available to every method in the class, and we’ll also be able to access these variables through any instance created from the class. The line self.make = make is a crucial step, as it takes the value associated with the parameter make and assigns it to the variable make, which is then attached to the object being created. The same process happens with self.model = model.
Remember self is not a keyword, and it is not mandatory to use the word self. It can be anything such as this or ABC, except it has to be the first parameter, but the convention of using self as the argument name is too strong.
Python Class Attributes
Think of a class as a blueprint for building something, like a car. Attributes are like details you find on that blueprint – describing the car. For example, if you have a class called Car, its attributes might be:
- make: The brand of the car (e.g., “Toyota,” “Ford”)
- model: The specific type of car (e.g., “Camry,” “Mustang”)
- color: The car’s color (e.g., “red,” “blue”)
Attributes tell you the characteristics of each car you build from the blueprint. Just like every car can have a different color, make, and model, each object you create from a class can have unique values for its attributes.
Adding Attributes using __init__()
Method (Approach 1)
Next, we will add instance attributes using a constructor method (__init__), which is loaded at the time of object creation. A code snippet with three instance attributes (make, model, and year) and the init method is shown next:
Example
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
Explanation
make
,model
, andcolor
are arguments you provide when creating a newCar
object.- Inside
__init__
, these arguments set the values of make, model, and color attributes for that specificCar
object.
Attributes within a class define the properties of that class. These properties define what’s unique about each car.
Adding Attributes on the Fly (Approach 2)
The Car class we created has no attributes or methods. It’s an empty class. In Python, you can add attributes on the fly without defining them in the class. The following snippet is a valid example of code in which we add attributes to a class instance at runtime:
Example
class Car:
pass
if __name__ == "__main__":
car = Car()
car.make = "Toyota"
car.model = "Camry"
car.year = 2023
print (car.make)
print (car.model)
print (car.year)
In this extended example, we created an instance (car) of our Car class and then added three attributes to this instance: make, model, and year. Note attributes added using this approach are instance attributes.
Setting a Default Value for an Attribute
Attributes can be defined without being passed in as parameters. These attributes can be defined in the __init__() method, where they are assigned a default value.
Let’s add an attribute called odometer_reading that always starts with a value of 0.
Example
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
When Python calls the __init__() method to create a new instance of a Car class, it stores the make, model, and year values as attributes. Then Python creates a new attribute called odometer_reading and sets its initial value to 0.
Python Class Methods
A method is a function defined within the class Car that allows a car object to perform an action.
Example
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def start_engine(self):
print(f"{self.make} engine started.")
Explanation
def start_engine(self):
: This line defines the method.def
indicates we’re defining a function.start_engine
is the name of the method (represents action).self
is a special keyword that refers to the current car object on which the method is called.print()
: When called, it prints a message.
Behavior: The methods (like start_engine) define what actions the car object can take.
Creating an Object
After you’ve created a class (like “Car“), you can use it to create objects. These objects are like the actual cars you build from the blueprint.
Here’s how you create an object in Python:
- Choose a name for your object: This is like giving your car a name (e.g., “my_car“).
- Use the class name followed by parentheses: This tells Python to build a new object based on your class.
Example
my_car = Car("Toyota", "Camry", 2023)
The above line creates a new object named my_car from Car class. When the object is created, the make, model, and year are set with values “Toyota”, “Camry”, and 2023 respectively.
This is like making a specific car based on the Car class. This particular car is a Toyota Camry from the year 2023.
Creating Multiple Objects
You can create as many instances from a class as you need. Let’s create a second car object called another_car:
my_car = Car("Toyota", "Camry", 2023)
another_car = Car("Honda", "Civic", 2021)
We create a car named Toyota and a car named Honda. Each car is a separate instance with its own attributes, capable of the same actions. You can make as many instances from one class as you need as long as you give each instance a unique variable name.
Calling a Constructor
The constructor is automatically called when an object is created:
my_car = Car("Toyota", "Camry", 2023)
After an object has been created, you should not directly call the constructor on that object again:
my_car.__init__("Toyota", "Camry", 2023) # Bad
The constructor can set a new Car object, but you should not call the constructor on an existing object. Instead, replace the object with a new one:
my_car = Car("Toyota", "Camry", 2023) # OK
You should never call a Python method that starts with a double underscore. All these methods are intended for specific internal purposes (in this case, to initialize a newly created object).
Using the Object
We created a Car class and then made a specific car object called my_car. Think of my_car as your unique car, with its make, model, and year. Now, let’s look at how we use this object:
Example
print(my_car.make) # Output: Toyota
print(my_car.model) # Output: Camry
my_car.start_engine() # Output: The engine has started.
Explanation
print(my_car.make)
: Accesses and prints the make attribute of the my_car object.print(my_car.model)
: Accesses and prints the model attribute of the my_car object.my_car.start_engine()
: Calls the start_engine method on the my_car object.
The above code demonstrates the core idea of OOP. We have an object (my_car) that represents a real-world thing (a car) and has both characteristics (make, model, year) and behaviors (start_engine).
Accessing Attributes
To access the attributes of an instance, you use dot (.) notation. We access the value of my_car’s attribute make by writing:
print(my_car.make) # Output: Toyota
Dot notation is often used in Python. This syntax demonstrates how Python finds an attribute’s value. Here, Python looks at the instance my_car and then finds the attribute name associated with my_car.
This is the same attribute referred to as self.make in the class Car. We use the same approach to work with the attribute model and year.
Calling Methods
After we create an instance from the class Car, we can use dot notation to call any method defined in Car. Let’s start our car:
my_car.start_engine() # Output: Toyota engine started.
To call a method, give the name of the instance (in this case, my_car) and the method you want to call, separated by a dot. When Python reads my_car.start_engine(), it looks for the method start_engine() in the class Car and runs that code.
Modifying Attribute Values
The simplest way to modify the value of an attribute is to access the attribute directly through an instance. Here we set the odometer reading to 55 directly:
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def start_engine(self):
print(f"{self.make} engine started.")
my_car = Car("Toyota", "Camry", 2023)
print(my_car.odometer_reading) # Before Change: Odometer Reading is 0
my_car.odometer_reading = 55
print(my_car.odometer_reading) # After Change: Odometer Reading is 55
We use dot notation to access the car’s odometer_reading attribute and set its value directly. This line tells Python to take the instance my_car, find the attribute odometer_reading associated with it, and set the value of that attribute to 55.
What’s self argument?
Remember that you can create as many instances as you want from each class; however, you store them in separate variables or data collections. Let’s create two instances from our Car class:
Example
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def start_engine(self):
print(f"{self.make} engine started.")
# Creating two instances of the Car class
my_car = Car("Toyota", "Camry", 2023)
another_car = Car("Honda", "Civic", 2021)
my_car.start_engine() # Output: Toyota engine started.
another_car.start_engine() # Output: Honda engine started.
Every method has a reference to the object on which it was invoked, stored in the self variable. For example, consider the method call:
another_car.start_engine()
When the method is called, the parameter variable self refers to the same object as another_car.
The self is like a name tag for each car. When you tell a car to start_engine(), it uses self to identify which car is being asked to start – is it the Toyota Camry or the Honda Civic? This way, the right car’s engine gets started.
So, self is like a self-reference for each object. It helps the object’s methods know which specific object they are working with, so they can access and change that object’s unique attributes (like make, model, and year).
Object References
In Python, a variable does not hold an object. It has the memory location of an object. The object itself is stored elsewhere.
We use the technical term object reference to denote the memory location of an object. When a variable contains the memory location of an object, we say that it refers to an object. For example, after the statement
my_car = Car("Toyota", "Camry", 2023)
the variable my_car refers to the Car object that was created. Technically, the constructor returns a reference to the new object, which is stored in the my_car variable.
Types of Constructors
In Python, the __init__ method is the constructor and is always executed when a new object is created. There are three types of constructors supported in Python, listed as follows:
Default Constructor
If you forget to define a constructor (__init__ method) in your Python class, don’t worry! Python automatically provides a basic, empty constructor. This default constructor creates the object but doesn’t set any initial properties. It’s like a blank canvas, ready for you to add details later.
Non-Parameterized Constructor
This type of constructor does not take any arguments except a reference to the instance being created. The following code sample shows a non-parameterized constructor for a Car class:
class Car:
def __init__(self):
print("A new instance of Car class is created")
Since no arguments are passed with this constructor, we have limited functionality to add to it. For example, in our sample code, we sent a message to the console that a new instance has been created for the Car class.
Parameterized Constructor
A parameterized constructor lets you customize your object when you create it. It accepts one or more values as arguments, which you can use to set the object’s initial properties. For example, in a Car class, a parameterized constructor might take arguments like “make,” “model,” and “year” so you can specify those details right when you create a new car object.
class Car:
def __init__(self, parameter_one, parameter_two):
self.p1 = parameter_one
self.p2 = parameter_two
Destructors
While constructors set up objects when created, destructors are responsible for cleaning them up when no longer needed. However, in Python, destructors aren’t as common due to Python’s automatic garbage collection, which removes unused objects for you. Still, if you need to perform specific actions when an object is deleted, you can use the special __del__ method. This method gets triggered automatically when all references to the object are gone. Here is the syntax for defining a destructor method in Python:
Example
def __del__(self):
print("Car Object is deleted.")
Instance Variables vs Class Variables
In Python, we have two main types of attributes:
- Class Variables
- Instance Variables
Instance Variables
Instance variables belong to each individual object created from a class. Each object gets its own unique copy of the instance variable.
Instance Variables Example
class Car:
def __init__(self, make, model, year):
self.make = make # These are instance variables
self.model = model
self.year = year
In a Car class, color, make, and model are instance variables because each car can have different values for them.
Class Variables
Class variables are shared among all objects of a class. There’s only one copy of a class variable; all objects access this same value. These variables are defined outside of any methods, usually at the top of the class definition.
Class Variables Example
class Car:
number_of_wheels = 4 # This is a class variable
def __init__(self, make, model, year):
self.make = make # These are instance variables
self.model = model
self.year = year
In a Car class, wheel_count could be a class variable since all cars of that class would typically have the same number of wheels.
Naming Conventions in Python Classes
Naming Rules for Python Classes:
- Use PascalCase (aka UpperCamelCase) for Class Names:
- Start every word with a capital letter, including the first.
- Examples: ClassName, Person, Product
- Attribute Names (Variables Inside the Class):
- Use all lowercase letters.
- Separate words with underscores (_).
- Examples: first_name, last_name, account_balance
- Use descriptive names: Choose names that tell you what the class does. Instead of C1, use Car or BankAccount.
- No spaces or dashes: Use underscores (_) to separate words in a class name, like My_Special_Class.
- Avoid single-letter names: These are hard to understand. Use Person instead of P.
- Follow the PEP 8 style guide: PEP 8 is the standard guide for writing clean Python code.
Benefits of Classes
- Organize code better: Classes keep related data and actions together, making your code neater.
- Reuse code easily: Create blueprints (classes) and make multiple objects from them, saving time.
- Easier teamwork: Classes make it simpler for multiple people to work on a project together.
- Model real-world things: Represent real-world objects like animals or vehicles in your code.
- Write flexible code: Change or add features to your objects without messing up the rest of your code.
When to Avoid Classes
- Small, simple tasks: If your code is short and easy, classes might be overkill.
- No shared data: If your functions work independently, there is no need for classes.
- Early learning stages: Focus on understanding functions and variables first.
- Performance critical: In rare cases, classes might slow your code.
- Alternative tools fit better: Sometimes, dictionaries or modules might be a more straightforward solution.
Conclusion
Python classes provide a powerful tool for organizing and structuring code. By defining classes, we create reusable blueprints for objects, encapsulating their data (attributes) and behaviors (methods). This enhances code readability, maintainability, and promotes the principles of object-oriented programming.