Home

 › 

Articles

 › 

Classes In Python: Fully Explained

Python vs. Java

Classes In Python: Fully Explained

Key Points

  • Python is a relatively simple object-oriented programming language that uses classes to implement encapsulation, inheritance, and polymorphism.
  • Classes in Python are like templates or blueprints used to create objects, with instances being specific implementations of a class with their own properties and behavior.
  • Creating a class in Python involves using the ‘class’ keyword, defining the ‘__init__()’ method to initialize attributes, and adding methods to define the behavior of the class.
  • There are different types of classes in Python, including abstract classes, metaclasses, derived classes, singleton classes, and mixin classes, each with their own purposes and applications.

When it comes to object-oriented programming languages, Python is a relatively simple one to use to implement classes. Using classes is a key factor in encapsulation, inheritance, and polymorphism, as well as making your code more modular. Whatever your experience level, understanding classes is extremely useful for helping you write better and cleaner code. In this article, we’re going to cover what classes in Python are, the types of classes, and how to use them.

What Are Classes in Python?

You can think of a class as a template or blueprint which is used to create objects. This is the general term, whereas specific occurrences of objects are known as instances. As such, instances are particular implementations of a class, with their own properties and behavior.

For example, if you want to record the types of cars being sold in a car dealership, you could represent these with the “Cars” class. Within this class, we could define attributes, such as color, model, speed, year, etc. Multiple instances can then be created to represent specific car types, which can be used with any methods defined in the class. Or, in simpler terms, classes can be considered like a generic house blueprint, where each house that’s built from the blueprint would be a class object. At a high level, the behavior of an object is indicated by its methods, while the object’s state is represented by its attributes.

Creating and Defining Classes

Creating a class isn’t too complicated, and always begins with using the “class” keyword, followed by the class name, with each word capitalized. We usually follow this by defining the “__init__()” method, which is used to initialize the attributes of any object we create. We can also define class methods and shared attributes at this stage. Using our car example, we could create a class as follows:

class Car:
    def __init__(self, make, model, year, color):
        self.make = make
        self.model = model
        self.year = year
        self.color = color
        self.is_running = False
        self.speed = 0

    def start_engine(self):
        if not self.is_running:
            self.is_running = True
            print("Engine has started.")
        else:
            print("Engine is already running.")

    def stop_engine(self):
        if self.is_running:
            self.is_running = False
            self.speed = 0
            print("Engine has stopped.")
        else:
            print("Engine is already stopped.")

    def accelerate(self, increment):
        if self.is_running:
            self.speed += increment
            print(f"Accelerated. Current speed: {self.speed} km/h.")
        else:
            print("Cannot accelerate. Engine is not running.")

    def brake(self, decrement):
        if self.is_running:
            if self.speed - decrement >= 0:
                self.speed -= decrement
                print(f"Braked. Current speed: {self.speed} km/h.")
            else:
                self.speed = 0
                print("Car stopped.")
        else:
            print("Cannot brake. Engine is not running.")

    def display_info(self):
        print("Car Information:")
        print(f"Make: {self.make}")
        print(f"Model: {self.model}")
        print(f"Year: {self.year}")
        print(f"Color: {self.color}")
        print(f"Speed: {self.speed} km/h")
        status = "Running" if self.is_running else "Stopped"
        print(f"Status: {status}")

car1 = Car("Toyota", "Camry", 2022, "Silver")
car2 = Car("Honda", "Accord", 2021, "Black")

car1.start_engine()
car1.accelerate(20)
car1.brake(5)
car1.display_info()

car2.start_engine()
car2.accelerate(30)
car2.brake(10)
car2.stop_engine()
car2.display_info()

First, we define the “Car” class and the “__init__()” constructor method. This takes the “model”, “year”, “make”, and “color” parameters, as well as “self”, which refers to the created instance. We then assign the parameter values to instance attributes, using the “self.[parameter]” syntax. Two extra attributes are also initialized, which represent the state of the engine and the car’s overall speed.

We then define some methods inside the class. These check if the engine has started or stopped and provide functionality to increase or decrease the car’s speed. We also define the “display()” method, which prints various attributes of the car instances.

We finish by creating two instances of the class, calling some methods on each, and printing the results, as can be seen in the image.

creating classes example python
Classes in Python are defined using the “class” keyword.

Class Attributes vs. Instance Attributes

We’ve briefly gone over what classes, attributes, and instances are, but it’s a good idea to distinguish between class and instance attributes. Class attributes are defined within the class, but not within any class methods. They’re also shared by all instances we create of the class objects and are accessed by using the class name or any instance. On the other hand, instance attributes are specific to each instance, defined within the “__init__()” method. Each instance has its own copy of these attributes. Accessing and modification of class and instance attributes are also done through the class or instances themselves, respectively. In our previous example, all the attributes we defined in the car class are instance attributes, because they’re defined within the constructor method, and each instance has its own set of these.

To illustrate the difference, consider the following code:

class Car:
    total_cars = 0

    def __init__(self, make, model):
        self.make = make
        self.model = model
        Car.total_cars += 1

car1 = Car("Toyota", "Camry")
car2 = Car("Honda", "Accord")

print(car1.total_cars)
print(Car.total_cars)

print(car1.make)
print(car1.model)

print(car2.make)
print(car2.model)

We have the same class here, and some instance attributes, “make” and “model”. However, we also have the class attribute, “total_cars”, which tracks the number of created cars. As such, it’s defined outside of any class methods. First, we access the class attribute through the “car1” instance, and then we access it directly, printing the same result each time. We finish by printing the “make” and “model” attributes of both instances, as can be seen in the image.

class vs instance attributes
Class attributes are shared among instances, but instance attributes are specific to each.

Types of Classes in Python

There are many different kinds of classes in Python. We’ve covered standard classes so far, but other common types include abstract, meta, derived, singleton, and mixin classes. A brief explanation of these follows.

Abstract classes

Abstract classes are called as such because they can’t be directly instantiated, and only provide a blueprint that other classes can use to implement methods and interfaces. They usually contain abstract methods, which also have no implementation present.

While Python doesn’t have an explicit abstract keyword, we can use the “ABC” class to create abstract classes, along with a decorator to modify the class. For example, we have this code:

from abc import ABC, abstractmethod

class AbstractClass(ABC):
    @abstractmethod
    def abstract_method(self):
        pass

    def regular_method(self):
        print("This is a regular method.")

class ConcreteClass(AbstractClass):
    def abstract_method(self):
        print("Implementation of abstract_method.")

obj = ConcreteClass()
obj.abstract_method()
obj.regular_method()

We define the “AbstractClass” class, and the method “abstract_method()”. We also define a regular method, “regular_Method”, and create the “ConcreteClass” class, which contains the implementation for the abstract method. Lastly, an instance of this class is created, both the methods called, and the results are printed.

abstract class example
Abstract classes provide methods but with no implementation.

Metaclasses

Metaclasses are those which allow you to define the behavior of other classes, usually indicating how they should be created. In this way, metaclasses can be thought of as a class of a class and they can be rather complex. However, an example of a metaclass was shown in the previous example; the “ABC” metaclass is used to create and define abstract classes and mark specific methods as abstract.

Derived classes

Derived classes are those which inherit behaviors, methods, and properties from another class. They can extend the base class with additional methods or attributes, or even by overriding other methods. Note that the “ConcreteClass” class in the previous example isn’t actually a derived class, since it merely provides a specific implementation for the abstract class. For a simple example, take a look at this code block:

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        print("The animal makes a sound.")

class Dog(Animal):
    def speak(self):
        print("The dog barks.")

animal = Animal("Generic Animal")
animal.speak()

dog = Dog("Fido")
dog.speak()

We have the base “Animal” class, but also the derived “Dog” class, which contains its own implementation for the “speak()” method. We create an instance of the base class, assign it to the “animal” variable, and print the generic message. After this, we create an instance of the derived class, assign it to the “dog” variable, and call the speak method on this object. This prints a specific message, which we can also see in the console in the image.

Derived class example
Derived classes are designed to inherit methods and properties from a base class.

Singleton classes

Singleton classes are ones which restrict the creation of instances to a single instance. They’re mostly used when we want to be able to globally access this instance with different objects when resources need to be shared and when we want to control the initialization. Using global states can be tricky as it can make code less modular, but singleton classes do have their applications. Here’s a simple example:

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

singleton1 = Singleton()
singleton2 = Singleton()

print(singleton1 is singleton2)

We create the “Singleton” class and define the “__new__()” method, which controls the creation of instances. The method checks if the “_instance” variable is none, upon which it creates an instance using the “super().__new__(cls)” method. When we create subsequent instances, the existing instance is returned. To finish, we create two instances, “singleton1” and “singleton2”, and check if they’re equivalent. They are shown to be the same through the “True” output, as we can see in the image.

singleton class example
Singleton classes only allow one instance of the class object to be created.

Mixin classes

If we need extra functionality but don’t want to use inheritance, mixin classes provide us with another way to achieve this. A mixin class is one that’s designed to be “mixed” with other classes so that it can inherit their properties. In this way, mixin classes add extra features to other classes. Usually, each mixin class provides a specific feature to the class without interrupting the hierarchy, which helps us keep our code modular and customizable. To illustrate, consider the following code:

class FlyMixin:
    def fly(self):
        print("Flying...")

class SwimMixin:
    def swim(self):
        print("Swimming...")

class Bird(FlyMixin):
    pass

class Duck(FlyMixin, SwimMixin):
    pass

bird = Bird()
bird.fly()

duck = Duck()
duck.fly()
duck.swim()

We start by creating the mixin class “FlyMixin”, making sure to add mixin as a suffix for easy identification. Inside this class, we define the “fly()” method, which prints the “Flying…” message. We then create the “SwimMixin” class, and the “swim()” method, with similar functionality.

After this, the “Bird” and “Duck” classes are created. The “Bird” class incorporates the “FlyMixin” class, while the “Duck” class incorporates both mixin classes. We finish by creating instances of both classes and calling the appropriate methods on these instances. The results can be seen in the image.

mixin class example
Mixin classes can provide modifications to other classes without interfering with inheritance.

Classes in Python: Wrapping Up

Classes are fundamental to any OOP language, and Python is no exception. Understanding how to use classes helps us to encapsulate our data, utilize inheritance effectively, and make our code reusable and customizable. Class attributes differ from instance attributes, in that they’re shared among all class instances. There are also many common types of classes. These regular classes, metaclasses, abstract classes, derived classes, singleton classes, and mixin classes. These all have their own applications, depending on your project’s needs. Gaining an appreciation for all of them will aid you in designing complex programs.

Summary Table

Class TypeDescription
Abstract ClassesCan’t be directly instantiated, only provide a blueprint that other classes can use to implement methods and interfaces.
MetaclassesAllow you to define the behavior of other classes, usually indicating how they should be created.
Derived ClassesInherit behaviors, methods and properties from another class. They can extend the base class with additional methods or attributes, or even by overriding other methods.
Singleton ClassesRestrict the creation of instances to a single instance. Mostly used when we want to be able to globally access this instance with different objects when resources need to be shared and when we want to control the initialization.
Mixin ClassesDesigned to be “mixed” with other classes so that it can inherit their properties. Add extra features to other classes without interrupting the hierarchy, which helps us keep our code modular and customizable.

Frequently Asked Questions

What are classes in Python?

A class is a blueprint or template used to create objects and indicates what properties and behaviors the objects should have.

What are attributes?

Attributes are variables that represent the properties of objects. Class attributes are shared among all instances, whereas instance attributes are specific to each instance.

How do inheritance and polymorphism relate to classes in Python?

Inheritance is where a class inherits methods, properties, or behaviors from another class, typically extends them, and is used to make code reusable. Polymorphism is where class objects are treated uniformly and helps to make code flexible.

What are metaclasses?

Metaclasses are sort of a class of a class, and are used to define the properties of other classes and how they’re created.

What are abstract classes?

Abstract classes don’t contain any implementation themselves but are designed to be inherited by other classes, which provide their own implementations.

What are mixin classes?

Mixin classes are designed to be incorporated into other classes and reused as needed. They can be used to avoid using traditional inheritance or disrupting an inheritance hierarchy.

What are class decorators?

Decorators are used to modify a class’ behavior, and also used to create abstract classes, along with the “ABC” metaclass.

What are singleton classes?

Singleton classes only allow a single instance of a class to be created.

What does the “__init__()” method do?

The “__init__()” is a special method, known as a double underscore method, which is called when a class object is created. The method initializes the attributes of the object and prepares it for use.

To top