January 26, 2022

Using Classes in Python

In this tutorial, we'll learn how to create and work with Python classes. In particular, we'll discuss what Python classes are, why we use them, what types of classes exist, how to define a class in Python and declare/adjust class objects, and many other things.

What Are Classes in Python?

Because Python is an object-oriented programming (OOP) language, everything in it represents an object. Lists, tuples, sets, dictionaries, functions, etc. are all examples of Python objects. Generally speaking, a Python object is an entity of data items and methods describing the behavior of those items.

In contrast, a Python class is a template, or constructor, used to create Python objects. We can think of it as a culinary recipe, where all the ingredients and their quantities, including their possible ranges, are listed, and the whole process of cooking is described step-by-step. In this case, we can compare a cake recipe to a class, and a cake cooked following that recipe to an object (i.e., an instance of that class). Using the same recipe (class), we can create many cakes (objects). This is exactly the scope of creating a class in Python: to define data elements and the rules establishing how these elements can interact and change their state — and then use this prototype to build various objects (instances of the class) in a predefined way, instead of creating them from scratch every time.

Types of Classes in Python

Beginning with Python 3, the terms class and type for Python native objects are identical, meaning that for any object x, the values of x.class and type(x) are equal. Let's confirm this:

a = 5
b = 'Hello World'
c = [1, 2, 3]

for var in [a, b, c]:
    print(type(var)==var.__class__)
True
True
True

There are several built-in classes (data types) in Python: integer, float, string, Boolean, list, range, tuple, set, frozenset, dictionary, and some other, rarely used ones:

a = 5.2
b = 'Hello World'
c = [1, 2, 3]
d = False
e = range(4)
f = (1, 2, 3)
g = complex(1, -1)

for var in [a, b, c, d, e, f, g]:
    print(var.__class__)
<class 'float'>
<class 'str'>
<class 'list'>
<class 'bool'>
<class 'range'>
<class 'tuple'>
<class 'complex'>

Built-in and user-defined functions have their own classes/types:

def my_func():
    pass

print(my_func.__class__)
print(min.__class__)
<class 'function'>
<class 'builtin_function_or_method'>

When we use additional Python libraries, such as pandas or NumPy, we can create objects of the classes/types related only to those libraries:

import pandas as pd
import numpy as np

s = pd.Series({'a': 1, 'b': 2})
df = pd.DataFrame(s)
arr = np.array([1, 2, 3])

print(s.__class__)
print(df.__class__)
print(arr.__class__)
<class 'pandas.core.series.Series'>
<class 'pandas.core.frame.DataFrame'>
<class 'numpy.ndarray'>

However, the real benefit of classes in Python is that we can create our own and use them to solve specific tasks. Let's see how.

Defining Classes in Python

To define a Python class, use the class keyword followed by the name of the new class and the colon. Let's create a very simple empty class:

class MyClass:
    pass

Pay attention to Python naming convention for classes: use the camel case style, where each word starts with a capital letter, and the words are written together, without any separators. Another highly recommended convention is to add a docstring: the first string inside the class constructor that briefly describes what the class is for. Let's add a docstring to our class:

class MyClass:
    '''This is a new class'''
    pass

The code above creates a new class object called MyClass. A curious side note here is that, because every object in Python is related to some class (type), the class/type of our new class (as well as all the other Python classes, including the built-in ones) is type:

print(MyClass.__class__)
print(type(MyClass))
<class 'type'>
<class 'type'>

Let's return to the main topic, though. In general, when defining a new class, we also create a new class object that contains all the attributes (variables and methods) related to that class. There are also some attributes with special meaning, those that start and end with double underscore and are related to all the classes. For example, the doc__ attribute returns the docstring of that class, or None, if no docstring was added.

To access a class attribute, use the dot (.) operator:

class TrafficLight:
    '''This is a traffic light class'''
    color = 'green'

    def action(self):
        print('Go')

print(TrafficLight.__doc__)
print(TrafficLight.__class__)
print(TrafficLight.color)
print(TrafficLight.action)

This is a traffic light class

<class 'type'>
green
<function TrafficLight.action at 0x00000131CD046160>

The function action() defined inside the TrafficLight class above is an example of a class method, while the variable color is a class variable.

Declaring Class Objects in Python

We can assign a class object to a variable, creating a new object (instance) of that class. We call this process instantiation. A class object assigned to a variable is a copy of that class with real values that distinguish this object from the others of the same class. Returning to our culinary example, it's a cake made from 370g of flour (when the range in the recipe was 350-400) and with candied fruit decorations on top, instead of chocolate.

A class object has the following properties:

  • state – the data (variables) of the object
  • behavior – the methods of the object
  • identity – the unique name of the object

Let's assign a class object of the TrafficLight class to a variable traffic:

class TrafficLight:
    '''This is a traffic light class'''
    color = 'green'

    def action(self):
        print('Go')

traffic = TrafficLight()

print(traffic.__doc__)
print(traffic.__class__)
print(traffic.color)
print(traffic.action)
print(traffic.action())

This is a traffic light class

<class '__main__.TrafficLight'>
green
<bound method TrafficLight.action of <__main__.TrafficLight object at 0x00000131CD0313D0>>
Go
None

We created a new object instance of the TrafficLight class called traffic and accessed its attributes using the object name (identity). Note that the class of the new object is different from the class of the class itself (main.TrafficLight instead of type). Also, the action attribute returns different values for the class instance and the class itself: a method object in the first case and a function object in the second. Calling the action() method on the traffic object (by specifying traffic.action()) gives "Go," which is, for now, the only possible output of this method of the TrafficLight class.

Another important thing to notice in the code above is that we used the self parameter in the function definition inside the class. However, when we called the action() method on the traffic object, we didn't add any arguments. This is how the self parameter works: every time a class instance calls one of its methods, the object itself is passed as the first argument. In other words, traffic.action() is equivalent to TrafficLight.action(traffic). More generally, when we define a Python class method with several parameters, create an object of this class, and call that method on the object, Python converts it under the hood according to the following scheme:

obj.method(arg1, arg2, ..., argN) ➡️ MyClass.method(obj, arg1, arg2, ..., argN)

Therefore, every Python class method must have this additional first parameter representing the object itself, even if it doesn't have any other parameters. It's advisable to call it self, according to Python naming convention.

Let's make our TrafficLight class more meaningful and, at the same time, introduce a new special method:

class TrafficLight:
    '''This is an updated traffic light class'''
    def __init__(self, color):
        self.color = color

    def action(self):
        if self.color=='red':
            print('Stop & wait')
        elif self.color=='yellow':
            print('Prepare to stop')
        elif self.color=='green':
            print('Go')
        else:
            print('Stop drinking 😉')

yellow = TrafficLight('yellow')
yellow.action()
Prepare to stop

We use the init() method (aka class constructor) to initialize the object's state (i.e., to assign all the class variables at the moment of object instantiation). In this case, we created a new Python class TrafficLight with two methods: init() to initialize the traffic light color and action() to suggest the corresponding action based on the traffic light's color.

Creating and Deleting Object Attributes in Python

It's possible to add a new attribute to a class object after its instantiation:

green = TrafficLight('green')
yellow = TrafficLight('yellow')

green.next_color = 'red'

print(green.next_color)
print(yellow.next_color)
red
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_3860/40540793.py in <module>
      5 
      6 print(green.next_color)
----> 7 print(yellow.next_color)

AttributeError: 'TrafficLight' object has no attribute 'next_color'

In the code above, we created a new attribute next_color for the green object and assigned it to "red." Since this attribute isn't in the TrafficLightclass definition, when we try to check it for another object (yellow), we get an AttributeError.

We can delete any attribute of a class object using the del statement:

print(yellow.color)
del yellow.color
print(yellow.color)
yellow
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_3860/1130729614.py in <module>
      1 print(yellow.color)
      2 del yellow.color
----> 3 print(yellow.color)

AttributeError: 'TrafficLight' object has no attribute 'color'
<__main__.TrafficLight object at 0x00000131CAD50610>
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_3860/808519506.py in <module>
      1 print(yellow)
      2 del yellow
----> 3 print(yellow)

NameError: name 'yellow' is not defined

Class and Instance Variables

The difference between class and instance variables is where their values were assigned in a class definition, which also determines the scope of the variables.

  • Class variables: assigned in the class declaration but outside any method definition (including the class constructor). They are related to all object instances of that class.
  • Instance variables: assigned inside a class method or constructor definition. They are unique to each object instance of that class.
class TrafficLight:
    '''This is an updated traffic light class'''

    # Class variable
    traffic_light_address = 'NYC_Cranberry_Hicks'

    def __init__(self, color):

        # Instance variable assigned inside the class constructor
        self.color = color

    def action(self):
        if self.color=='red':

            # Instance variable assigned inside a class method
            self.next_color = 'yellow'
            print('Stop & wait')
        elif self.color=='yellow':
            self.next_color = 'green'
            print('Prepare to stop')
        elif self.color=='green':
            self.next_color = 'red'
            print('Go')
        else:
            self.next_color = 'Brandy'
            print('Stop drinking 😉')

# Creating class objects
for c in ['red', 'yellow', 'green', 'fuchsia']:
    c = TrafficLight(c)
    print(c.traffic_light_address)
    print(c.color)
    c.action()
    print(c.next_color)
    print('\n')
NYC_Cranberry_Hicks
red
Stop & wait
yellow

NYC_Cranberry_Hicks
yellow
Prepare to stop
green

NYC_Cranberry_Hicks
green
Go
red

NYC_Cranberry_Hicks
fuchsia
Stop drinking 😉
Brandy

For all the class instances above, we have the same value of the traffic_light_address variable, which is a class variable. The color variable was assigned inside the class constructor, and the next_color variable was calculated inside the action() class method based on the value of color for each class instance. These two are instance variables.

Conclusion

To sum up, we have discussed many aspects of creating and using Python classes:

  • What Python classes are and when to use them
  • The different types of Python built-in classes
  • The relationship between the terms class and type for a Python object
  • How to define a new class in Python
  • Python naming convention for classes
  • What class attributes are and how to access them
  • How to instantiate a class object
  • The properties of a class object
  • What the self parameter is and how it works
  • The properties of the class constructor
  • How to access, create, or delete class object attributes
  • The difference between class and instance variables

Now you have a complete toolkit to start working with classes in Python!

Elena Kosourova

About the author

Elena Kosourova

Elena is a petroleum geologist and community manager at Dataquest. You can find her chatting online with data enthusiasts and writing tutorials on data science topics. Find her on LinkedIn.