Classes

As programs grow in size and complexity, managing and organizing code can become quite challenging. Functions and variables might be scattered across different parts of a program, making it hard to keep track of what's going on and leading to messy, hard-to-maintain code. This is where classes, a cornerstone of object-oriented programming, come into play.
💡
Classes are a way of bundling related data and functions, creating what we call 'objects'. Classes are the fundamental concepts in object-oriented programming (OOP).
Classes are like blueprints for creating objects in our code. Each class wraps up related properties (data) and methods (functions) into single units. For example, in a game program, you might have classes like Player, Monster, or Item, each containing its own relevant data and methods. This makes it easier to understand and manage large codebases, as related functionalities are grouped, and it becomes clear how they interact with each other.
Let’s say you want to create software to model a library. You may have books in your library, so you'll need to create a Book class:
class Book:
    def __init__(self, title, author, pages):
        self.title = title     # Assign title to the book instance
        self.author = author   # Assign author to the book instance
        self.pages = pages     # Assign number of pages to the book instance
The class keyword introduces a new class, followed by its name (Book). The def __init__(self, title, author, pages): line defines the initial state of the class or the constructor. This is where the object gets initialized. self refers to the instance of the class. title, author, and pages are attributes of the class.
You can create a new book object by calling the class like a function:
# Create a new instance of Book
mockingbird = Book('To Kill a Mockingbird', 'Harper Lee', 281)

print(mockingbird.title)   # To Kill a Mockingbird
print(mockingbird.author)  # Harper Lee
print(mockingbird.pages)   # 281
Notice that we pass To Kill a Mockingbird, Harper Lee, and 281 as arguments. Those get passed as arguments to the __init__ method (almost like a regular function).
We can create several instances of the Book class:
# create more book instances
book2 = Book('1984', 'George Orwell', 328)
book3 = Book('The Great Gatsby', author='F. Scott Fitzgerald', pages=180)
book4 = Book('Moby Dick', 'Herman Melville', pages=720)

# print some information about the books
print(f'{book2.title} by {book2.author} has {book2.pages} pages.')  # 1984 by George Orwell has 328 pages.
print(f'{book3.title} by {book3.author} has {book3.pages} pages.')  # The Great Gatsby by F. Scott Fitzgerald has 180 pages.
print(f'{book4.title} by {book4.author} has {book4.pages} pages.')  # Moby Dick by Herman Melville has 720 pages.
Just like with functions, we can pass both positional and keyword arguments to the __init__ method.
In addition to data, classes can also encapsulate functionality. Suppose, in our library system, we want to mark a book as read. We can define a method in our Book class for this purpose:
class Book:
    def __init__(self, title, author, pages):
        self.title = title     # Assign title to the book instance
        self.author = author   # Assign author to the book instance
        self.pages = pages     # Assign number of pages to the book instance
        self.is_read = False   # Book has not been read yet

    def mark_as_read(self):    # A class method
        self.is_read = True    # Mark the book as read


mockingbird = Book('To Kill a Mockingbird', 'Harper Lee', 281)
print(mockingbird.is_read)   # False, book has not been read yet
mockingbird.mark_as_read()   # Mark the book as read
print(mockingbird.is_read)   # True, book has been read
The mark_as_read method changes the state of the is_read attribute to True. We can call this method on any book instance. This demonstrates how we can bundle related data and functionality together using classes in Python.
💡
In Python, self is a conventional name for the first parameter in instance methods of a class. It's a reference to the current instance of the class. self is used to access the attributes and methods of the class within its definition. When you create a new object of the class, Python automatically binds the self argument to that new object, which is why you don't pass self when you call an instance method. Although self isn't a reserved keyword in Python, it's widely used because of the clear and readable style it encourages. It's important to note that you could use any other name, but using self is strongly recommended by the community and is considered a best practice.

Challenge: Create a Car Class

You are tasked to create a Car class that should have the following attributes:
  • color (the color of the car)
  • make (the brand of the car)
  • model (specific model of the car)
  • year (the year it was made)
These attributes should be initialized in the __init__ method of the class.
In addition, the Car class should have a display_details method. This method should return a string representation of the car's details in the format [year] [color] [make] [model].
Input
Output
c = Car('red', 'Ferrari', 'F8', 2023); print(c.display_details())
2023 red Ferrari F8
c = Car('black', 'Tesla', 'Model S', 2021); print(c.display_details())
2021 black Tesla Model S
 

Constraints

Time limit: 2 seconds

Memory limit: 512 MB

Output limit: 1 MB

To check your solution you need to sign in