What Is a Constructor in Python?

A construction site with the title of the article overlayed

Today, we’re talking about constructors! Specifically, we’ll look at the __init__() special method in Python, which functions as a constructor. Let’s get into it.

Table of Contents

Concept Overview

In the world of object-oriented programming languages, we come across this concept known as a constructor. Put as simply as I can, a constructor creates an object.

One way I like to think about this is in terms of construction sites, like building a house. In this analogy, the house is built from a blueprint (i.e., the instructions for how to build a house), and a blueprint is like a class. Therefore, the construction worker is the one who actually builds the house—like how a constructor builds an object.

Extending the analogy, a construction worker can use the same blueprint to make many different houses. Much like how a constructor can use the same class to make many different objects.

With all that said, constructors only make sense when a class is involved. As a result, to write a constructor in Python, we need a class. For today, we’ll keep the house theme and make a basic House class:

class House:
  pass

Right now, this class doesn’t do anything because it has no fields or methods (beyond the default fields and methods). We can give it some more interesting behavior by creating the constructor:

class House:
  def __init__(self):
    pass

Right off the bat, you’ll probably recall that we’re looking at a special method. Again, it doesn’t really do anything. To give it more interesting behavior, we have to add parameters to the method. To do that, we’ll pick a couple high-level attributes of housing, like the number of bedrooms and baths:

class House:
  def __init__(self, num_beds, num_baths):
    pass

Of course, the constructor isn’t quite finished. We need to make use of these parameters, so let’s make some instance variables:

class House:
  def __init__(self, num_beds, num_baths):
    self.num_beds = num_beds
    self.num_baths = num_baths

And, that’s it! We have a House which we can construct with different numbers of beds and baths.

Naturally, that answers the question of what a constructor is, but I’m certain you have more questions now. Let’s take a look at a few.

How Do I Use a Constructor?

Once we have a class with a constructor, it’s only useful if we can turn it into an object. To do that, we just need to use the class name directly:

my_house = House(3, 1.5)
your_house = House(5, 2)

Again, that’s it! We now have two different house objects with different numbers of bedrooms and baths.

How Do I Set Default Arguments in a Constructor?

Because the constructor is just a special method, it allows for all the same features of other methods. Therefore, if you want some sort of default behavior for your constructor, you can set defaults to the constructor parameters:

class House:
  def __init__(self, num_beds=3, num_baths=2):
    self.num_beds = num_beds
    self.num_baths = num_baths

With the defaults setup, a user can use your constructor in a variety of new ways:

my_house = House(3, 1.5)          # provide all arguments in order
your_house = House(5)             # provide only the first argument
their_house = House(num_baths=1)  # provide keyword arguments
default_house = House()           # provide no arguments at all

How Do I Overload the Constructor?

For better or worse, Python doesn’t really have support for method overloading. If you’re not familiar with this concept, it’s basically the idea that we can have multiple methods with the same name but different parameters.

A common use case for overloading might be to have an empty constructor that initializes the fields to some defaults, a basic constructor with whatever you want the user to provide, and a copy constructor which takes in an object of the same type and copies it.

If you want to replicate this behavior, you’re somewhat stuck doing it through the constructor parameters directly. For example, you might expand the constructor to include the option for a house. If that parameter exists, you treat the constructor like a copy constructor. Otherwise, you prioritize the other parameters:

class House:
  def __init__(self, num_beds=3, num_baths=2, house_copy=None):
    self.num_beds = num_beds
    self.num_baths = num_baths
    if house_copy:
      self.num_beds = house_copy.num_beds
      self.num_baths = house_copy.num_baths

As you can imagine, this leads to a lot of weirdness. For instance, what if the user provides all three arguments? Maybe you throw an error, or maybe you silently let the house overwrite the values.

Other ways I’ve seen this done is through a process of manual type checking, but that seems like a bit of a nightmare, especially if you’re looking to accept more than one parameter.

After some searching around, it looks like the Python developers discussed adding some features to allow for method overloadingOpens in a new tab., but I don’t believe they’ve ever been added. Though, it looks like there’s an @overload decorator in the typing moduleOpens in a new tab. that may provide this feature, but I haven’t toyed with it. It also looks like there is some single dispatch feature released in the Python 3.4Opens in a new tab.. Ultimately, I’m not sure if any of these features apply to special methods like the constructor. Feel free to explore and let me know!

Alternatively, you can make use of the @classmethod decorator to provide (in Java terms) static methods that produce objects in certain initial states. Of course, rather than calling the House() constructor, you would make a static method call like House.new_house():

class House:
  def __init__(self, num_beds=3, num_baths=2):
    self.num_beds = num_beds
    self.num_baths = num_baths

  @classmethod
  def from_house(cls, house_copy):
    return cls(house_copy.num_beds, house_copy.num_baths)

Ultimately, it’s up to you to figure out what makes the most sense for your work.

Constructing Your Future

As expected, introducing the concept of constructors opens up a massive can of worms. In the future, I’ll need to cover concepts like objects, methods, and parameters. I’m already enjoying watching the concept map grow!

While you’re here, I’d love it if you read some of these related articles:

In addition, you can build up your Python knowledge by getting one of these (#ad):

If you really enjoy the work, I’d recommend checking out my list of ways to grow the site. Come be a part of the community by joining our Discord or hopping on the Patreon. Otherwise, take care! I’ll see you soon.

The Python Concept Map (15 Articles)—Series Navigation

An activity I regularly do with my students is a concept map. Typically, we do it at the start and end of each semester to get an idea of how well our understanding of the material as matured over time. Naturally, I had the idea to extend this concept into its own series, just to see how deeply I can explore my own knowledge of Python. It should be a lot of fun, and I hope you enjoy it!

Jeremy Grifski

Jeremy grew up in a small town where he enjoyed playing soccer and video games, practicing taekwondo, and trading Pokémon cards. Once out of the nest, he pursued a Bachelors in Computer Engineering with a minor in Game Design. After college, he spent about two years writing software for a major engineering company. Then, he earned a master's in Computer Science and Engineering. Today, he pursues a PhD in Engineering Education in order to ultimately land a teaching gig. In his spare time, Jeremy enjoys spending time with his wife and kid, playing Overwatch 2, Lethal Company, and Baldur's Gate 3, reading manga, watching Penguins hockey, and traveling the world.

Recent Code Posts