Classes in Python are essentially blueprints for creating objects. They encapsulate data for the object and methods to manipulate that data.
To understand classes, imagine a class as the architectural plan for a building. This plan outlines the structure of the building, including all its components like rooms, doors, and windows. Just as a building is constructed based on its plan, in Python, an object is an instance of a class, built according to the class's blueprint.
In Python, we use the class
keyword to define a class. Consider the example below where we define a class Vehicle
:
class Vehicle:
# class definition
In this case, Vehicle
is the name of the class.
Let's explore this concept further with a specific example:
class Car:
model = ""
year = 0
Here, Car
is the class name, and model
and year
are attributes with default values ""
(an empty string) and 0
, respectively. Attributes in a class are akin to properties or characteristics of the class.
When we talk about objects in Python, we refer to them as instances of a class. For instance, if Car
is a class, we can create objects like car1
, car2
, etc., from this class. The syntax for creating an object is:
objectName = ClassName()
For example:
# create class
class Car:
model = ""
year = 0
# create objects of class
car1 = Car()
In this example, car1
is an object or instance of the Car
class. We can use this object to access and manipulate the class's attributes.
To interact with class attributes, we use dot notation. For instance:
# modify the model property
car1.model = "Sedan"
# access the year property
car1.year = 2019
Here, we've used car1.model
and car1.year
to update and access the model
and year
attributes, respectively.
Let's consider a more comprehensive example to illustrate these concepts:
Example 1: Python Class and Objects
# define a class
class Car:
model = ""
year = 0
# create object of class
car1 = Car()
# access attributes and assign new values
car1.year = 2019
car1.model = "Sedan"
print(f"Model: {car1.model}, Year: {car1.year}")
Output:
Model: Sedan, Year: 2019
In this example, we've defined a class named Car
with two attributes: model
and year
. We've then created an object car1
of the Car
class and accessed and modified its properties using dot notation.
We can also create multiple objects from a single class. For instance:
# define a class
class Worker:
# define a property
worker_id = 0
# create two objects of the Worker class
worker1 = Worker()
worker2 = Worker()
# access property using worker1
worker1.worker_id = 3001
print(f"Worker ID: {worker1.worker_id}")
# access properties using worker2
worker2.worker_id = 3002
print(f"Worker ID: {worker2.worker_id}")
Output:
Worker ID: 3001
Worker ID: 3002
In this scenario, we've created two distinct objects worker1
and worker2
from the Worker
class and assigned unique worker_id
s to each.
Methods in Python are functions defined inside a class. They are used to define the behaviors of an object. For instance:
# create a class
class Room:
length = 0.0
width = 0.0
# method to calculate area
def calculate_area(self):
return self.length * self.width
# create object of Room class
living_room = Room()
# assign values to properties
living_room.length = 20.0
living_room.width = 15.0
# access method inside class to calculate area
area = living_room.calculate_area()
print(f"Area of Living Room: {area}")
Output:
Area of Living Room: 300.0
In this example, the Room
class has two attributes (length
and width
) and a method calculate_area
which computes the area of the room. We created an object living_room
, assigned values to its attributes, and called its calculate_area
method to calculate and print the area.
Constructors in Python are special methods used to initialize new objects. They are defined by the __init__()
method. Here's how you can use a constructor in Python:
class Car:
# constructor function
def __init__(self, model = "", year = 0):
self.model = model
self.year = year
car1 = Car("Sedan", 2019)
Here, __init__()
is the constructor function that's automatically invoked when a new object of the Car
class is created. This constructor initializes the model
and year
attributes of the object.
This example demonstrates how a constructor can set the initial state of a new object, allowing us to create objects with predefined attributes.
The self
keyword in Python can be likened to a personal pronoun in human languages like "I" or "myself." It's used within a class to refer to the instance of the class itself. It helps differentiate between the instance’s attributes and methods from those of other instances or the class itself.
Let's use an analogy of a classroom to explain the concept of self
. Imagine a classroom where each student can speak about themselves - their own name, their own grades, and their own belongings.
Classroom (Class): The classroom is like the class in Python. It's the blueprint that defines the structure and behavior of the students (objects) within it.
Students (Objects): Each student in the classroom is like an object in Python, created from the blueprint of the classroom (class). Every student has their own attributes (name, grades, etc.) just like objects have attributes (variables).
Referring to Oneself (Self): When a student talks about themselves, they refer to themselves as "I" or "me." This self-reference is crucial because it distinguishes their identity from that of other students. In Python, self
serves a similar purpose. Inside a class, when an object wants to refer to its own attributes or methods, it uses self
.
For example, if a student named Alice wants to talk about her grades, she doesn't just say "grades" (which could be anyone's grades in the classroom). Instead, she says "my grades," clearly indicating that she's talking about her own grades, not someone else's.
Similarly, in Python:
class Student:
def __init__(self, name, grades):
self.name = name # Here, 'self' ensures 'name' is associated with the specific instance.
self.grades = grades # Similarly, 'self.grades' refers to the 'grades' of the specific instance.
def introduce(self):
print(f"My name is {self.name} and my grades are {self.grades}.") # 'self' refers to the specific object calling this method.
When we create an instance of Student
:
alice = Student("Alice", 92)
And when alice
calls the introduce
method:
alice.introduce()
The self
in the introduce
method knows it's referring to the alice
instance of Student
. So, it correctly accesses Alice's
name and grades, and not someone else's. Without self
, Python wouldn't know which specific object's name and grades you're referring to, similar to how saying just "grades" in the classroom wouldn't be specific enough.
The __str__
method in Python is akin to giving an object the ability to understand and represent itself as a string in a human-readable form. It's one of the special or "dunder" (double underscore) methods in Python, intended to provide a meaningful string representation of an instance of a class.
Imagine you have a robot. This robot can perform various tasks, but you also want it to be able to introduce itself and describe what it is in a way that's understandable to humans. The __str__
method is like programming this self-description into the robot.
Here's a more detailed breakdown:
Purpose: The __str__
method is called when you use the print()
function on an object or when you use the str()
function to convert an object to a string. The method should return a string representation of the object.
Human-Readable: The string returned by __str__
is intended to be human-readable. It should provide a description of the object that makes sense to someone reading it.
Customization: Without a custom __str__
method, the default string representation provided by Python for an object isn't very informative (it's usually something like <__main__.MyClass object at 0x000002C572F6E400>
). By defining your own __str__
method, you can provide a much more useful and readable description.
Let's see an example to illustrate this:
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def __str__(self):
return f"{self.year} {self.make} {self.model}"
# Create a new car instance
my_car = Car("Tesla", "Model Y", 2021)
# Print the car object
print(my_car)
Output:
2021 Tesla Model Y
In this example:
We define a Car
class with attributes for make, model, and year.
We define the __str__
method to return a formatted string that provides a human-readable description of a Car
instance.
When we print my_car
, Python automatically calls the __str__
method, which returns "2021 Tesla Model Y".
Without the __str__
method, printing my_car
would give you something less informative, like <__main__.Car object at 0x000002C572F6E400>
. With __str__
, you get a meaningful description of the car, making your code more readable and your objects more understandable.