Python Example Class

The very basic Python example class is one with a name and a property.

For instance:

class Weight:
    kilos = 100

With this class, you can create weight objects and change their weights:

w1 = Weight()
w1.kilos = 200
print(w1.kilos)

Output:

200

Let’s see some other useful class examples in Python.

Python Class with Methods Example

A super useful feature of classes is that you can add methods into the class. You can then call these methods on the objects of the class.

For example, let’s create a Weight class. Let’s enable converting kilos to pounds with a method:

class Weight:
    kilos = 100

    def as_pounds(self):
        return self.kilos * 2.208

Now it is possible to call the as_pounds() method on any Weight instance:

weight1 = Weight()
weight1.kilos = 300

print(weight1.as_pounds())

Output:

662.4000000000001

Class with Special Methods Example

Python classes can have special methods or double-underscore methods.

Initialization Example

The most popular double-underscore method in Python is the __init__() method. This method is responsible for initializing the new object with an initial state.

For example, a person can be given a name and age upon creation.

For example, let’s create a Person class and an initializer to it that accepts name, weight, height, and age:

class Person:
    def __init__(self, name, weight, height, age):
        self.name = name
        self.weight = weight
        self.height = height
        self.age = age

Now it is possible to create new Person objects by for example:

soccer_player = Person("Jack", 80, 182, 30)
tennis_player = Person("Rose", 60, 163, 23)

The above code created two Person objects, a soccer player and a tennis player.

String Representation Example

We are going to continue working with the Person class.

Let’s next create a textual representation for the class Person. This way you can obtain useful information about the object.

Why?

Because now if you try to print a person, you get nonsense back:

print(soccer_player)
print(tennis_player)

Output:

<__main__.Person object at 0x1072d0fd0>
<__main__.Person object at 0x1072d0f10>

To get a user-friendly output when calling print() on an object, override the __str__ method in the class.

class Person:
    def __init__(self, name, weight, height, age):
        self.name = name
        self.weight = weight
        self.height = height
        self.age = age

    def __str__(self):
        return f"This person is {self.name}. They weigh {self.weight} kilos and are {self.height} centimeters tall. They are {self.age} years old."

Let’s create two persons:

soccer_player = Person("Jack", 80, 182, 30)
tennis_player = Person("Rose", 60, 163, 23)

Now you can get useful information about these persons because you just override the special methods __str__ and __repr__:

print(soccer_player)
print(tennis_player)

Output:

This person is Jack. They weigh 80 kilos and are 182 centimeters tall. They are 30 years old.
This person is Rose. They weigh 60 kilos and are 163 centimeters tall. They are 23 years old.

This is cool for the end-user for example as they now can see who the Person object is.

But what about us developers? We would like to see how this user object was created.

To create a developer-friendly representation of a Person object, override the __repr__ method in the class.

Here is how the Person class looks like after that:

class Person:
    def __init__(self, name, weight, height, age):
        self.name = name
        self.weight = weight
        self.height = height
        self.age = age

    def __str__(self):
        return f"This person is {self.name}. They weigh {self.weight} kilos and are {self.height} centimeters tall. They are {self.age} years old."
    
    def __repr__(self):
        return f"Person(name={self.name}, weight={self.weight}, height={self.height}, age={self.age})"

Now you can test it:

soccer_player = Person("Jack", 80, 182, 30)

# User-friendly info
print(soccer_player)

# Developer-friendly info
print(repr(soccer_player))

Output:

This person is Jack. They weigh 80 kilos and are 182 centimeters tall. They are 30 years old.
Person(name=Jack, weight=80, height=182, age=30)

Comparisons Example

Let’s continue with the Person class:

soccer_player = Person("Jack", 80, 182, 30)
tennis_player = Person("Rose", 60, 163, 23)

Let’s compare these objects:

print(soccer_player == tennis_player)

Output:

False

This is not a surprising result. As the soccer_player is a different object than the tennis_player, they are not the same object.

But if we do a greater than comparison:

print(soccer_player > tennis_player)

We get an error:

TypeError: '>' not supported between instances of 'Person' and 'Person'

This happens because comparing Person objects this way is meaningless. You could compare the age, name, height, weight, or whatever. But the Python interpreter has no idea what our intention is.

To overcome this, you can specify what should happen when calling the greater-than operator (>)on two Person objects.

To do this, override the __gt__() method in the Person class.

For example, let’s make it possible to compare the Person objects by their age using the greater than operator:

class Person:
    def __init__(self, name, weight, height, age):
        self.name = name
        self.weight = weight
        self.height = height
        self.age = age

    def __str__(self):
        return f"This person is {self.name}. They weigh {self.weight} kilos and are {self.height} centimeters tall. They are {self.age} years old."

    def __repr__(self):
        return f"Person(name={self.name}, weight={self.weight}, height={self.height}, age={self.age})"
    
    def __gt__(self, other_person):
        return self.age > other_person.age

Now you can compare two objects with a greater-than operator:

soccer_player = Person("Jack", 80, 182, 30)
tennis_player = Person("Rose", 60, 163, 23)

print(soccer_player > tennis_player)

Output:

True

Now the greater-than comparison works.

However, now doing a less-than comparison fails. This is because you only specified how the greater-than comparison should work. To allow comparing with the less-than operator, you need to override the __lt__() method.

Before we do that, let’s keep in mind there are other comparison operators too (<, >, <=, >=, ==, !=). If we override the behavior of one of them, we should override the rest of the operators to reflect the behavior.

This table shows you which method you need to override to customize the behavior of a comparison operator:

__eq__Equal
__ne__Not equal
__lt__Less than
__gt__Greater than
__le__Less than or equal
__ge__Greater than or equal

Let’s override each method in the above table to compare Person objects by their age. Here is the updated version of the Person class:

class Person:
    def __init__(self, name, weight, height, age):
        self.name = name
        self.weight = weight
        self.height = height
        self.age = age

    def __str__(self):
        return f"This person is {self.name}. They weigh {self.weight} kilos and are {self.height} centimeters tall. They are {self.age} years old."

    def __repr__(self):
        return f"Person(name={self.name}, weight={self.weight}, height={self.height}, age={self.age})"

    def __eq__(self, other_person):
        return self.age == other_person.age

    def __ne__(self, other_person):
        return not self.age == other_person.age

    def __lt__(self, other_person):
        return self.age < other_person.age

    def __gt__(self, other_person):
        return self.age > other_person.age

    def __ge__(self, other_person):
        return self.age >= other_person.age
    
    def __le__(self, other_person):
        return self.age <= other_person.age

Now you can make sure that the age-based comparisons work:

soccer_player = Person("Jack", 80, 182, 30)
tennis_player = Person("Rose", 60, 163, 23)

print(soccer_player == tennis_player)
print(soccer_player != tennis_player)

print(soccer_player < tennis_player)
print(soccer_player > tennis_player)

print(soccer_player >= tennis_player)
print(soccer_player <= tennis_player)

Output:

False
True

False
True

True
False

Class Inheritance Example

Given the Person class we implemented, let’s inherit it to a Student class. This is reasonable because each student is also a person:

class Student(Person):
    def __init__(self, name, weight, height, age, graduation_year):
        super().__init__(name, weight, height, age)
        self.graduation_year = graduation_year
    
    def greet(self):
        print(f"Hello, my name is {self.name}. I will graduate in {self.graduation_year}")

Now the student has all the properties the Person class has. In addition, it has its own property graduation_year and a greet() method.

Now you can use this class:

student1 = Student("Sam", 80, 188, 23, 2023)
student1.greet()

Output:

Hello, my name is Sam. I will graduate in 2023

And as this class inherits the comparison properties of the Person class, you can also make comparisons with Student objects:

math_student = Student("Alice", 80, 182, 28, 2022)
physics_student = Student("Rose", 60, 163, 26, 2023)

print(math_student == physics_student)
print(math_student != physics_student)

print(math_student < physics_student)
print(math_student > physics_student)

print(math_student >= physics_student)
print(math_student <= physics_student)

Output:

False
True

False
True

True
False

Further Reading