Get one quick Python tip each week Weekly Python advice: one quick Python tip every week

Making a singleton in Python

Share
Copied to clipboard.
Series: Classes
Trey Hunner smiling in a t-shirt against a yellow wall
Trey Hunner
5 min. read 4 min. video Python 3.7—3.11

How can you make a singleton in Python?

What is a singleton?

A singleton class is a class that only allows creating one instance of itself.

None is an example of a singleton object in Python. The class of None is NoneType:

>>> type(None)
<class 'NoneType'>

If we try to call the NoneType class, we'll get back an instance of that class.

>>> new_none = type(None)()

But every instance of the NoneType class is identical to every other instance of the NoneType class:

>>> new_none is None
True

So there's only one instance of NoneType in Python, and it's None.

Making a singletons in Python with a custom constructor

Here we have a class called EventTracker that helps us keep track of events in our application:

class EventTracker:

    def __init__(self):
        self.api_url = "http://example.com"

    def track(self):
        print(f"TODO track event at {self.api_url}")

We'd like to share just one instance of this class for our whole Python process. To do that, we could make a singleton class which only allows one instance of itself to be created.

We can make a singleton class by customizing our class to have a custom constructor method:

class EventTracker:
    _self = None

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

    def __init__(self):
        self.api_url = "http://example.com"

    def track(self):
        print(f"TODO track event at {self.api_url}")

Python's __init__ method is called the initializer method.

By the time the __init__ method gets called, our class instance has already been constructed. That's what the self argument in a method is:

    def __init__(self):
        ...

The __new__ method is the constructor method. Its job is to do the actual work of constructing and then returning a new instance of our class:

class EventTracker:
    _self = None

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

    ...

In this EventTracker class, our constructor method case always returns the same instance of our class.

If it doesn't have a class instance yet, it calls its parent class's constructor (that's object.__new__ since object is the parent class of all Python classes by default):

        if cls._self is None:
            cls._self = super().__new__(cls)

If we do already have a class instance, we just return it:

        return cls._self

So every "instance" of our class is actually the same instance.

Meaning when we first call our class, we'll get back a new instance:

>>> tracker = EventTracker()
>>> tracker
<__main__.EventTracker object at 0x7f32bdd780a0>

But if we call our class a second time, we'll get back the same exact instance:

>>> tracker2 = EventTracker()
>>> tracker2
<__main__.EventTracker object at 0x7f32bdd780a0>
>>> tracker2 is tracker
True

Every instance of our class is the same, which means we've made a singleton class.

We could use a global object instead

Creating a singleton class by making a custom constructor does work, but it might seem a little bit misleading to someone using this class. It's counter-intuitive that every time we call our class we'll always get back the same class instance.

The singleton pattern usually doesn't make sense in Python in its purest form. Instead, it usually makes more sense to make a single instance of a class, and then assign that instance to a global variable in our module.

Here we've renamed our class to _EventTracker (putting an _ prefix just before it to denote "private by convention"):

class _EventTracker:

    def __init__(self):
        self.api_url = "http://example.com"

    def track(self):
        print(f"TODO track event at {self.api_url}")


tracker = _EventTracker()

It isn't strictly necessary to rename your class, but it does let people know that you're not actually meant to use the class directly. You're only ever meant to interact with this one instance.

When using our class, we won't actually interact with the class directly. Instead we would import and use just the single class instance we've made:

>>> from events import tracker
>>> tracker.track()
TODO track event at http://example.com

Do we even need a singleton class?

If there's never any reason to have two instances of your class, you might consider not making a class at all and instead just use the global state within your module.

Here we've made an events module that does the same thing as our events module before:

api_url = "http://example.com"


def track():
    print(f"TODO track event at {api_url}")

But we don't have a class. Instead, we've taken the state and the functionality that was within that class, and we've put it at the module level.

To use this module, instead of saying events.tracker.track() like we would've done before, we can just use events.track():

>>> import events
>>> events.track()
TODO track event at http://example.com

We're now calling our track function at the module level.

Now, this works for the same reason that making global object works: modules in Python act like singletons!

Python's modules act like singletons

Classes are handy, but you don't always need a class in Python.

When you import a module, Python will run the code within that module and create a new module object:

>>> events
<module 'events' from '/home/trey/events.py'>

But if we import the same module again, Python will give us back the exact same module object:

>>> import events as again
>>> again
<module 'events' from '/home/trey/events.py'>
>>> again is events
True

So if we change some of the global state within one of these module objects:

>>> again.api_url
'http://example.com'
>>> again.api_url = "NEW URL"

That change would be reflected in the other object as well (because those two variables point to the same object):

>>> events.api_url
'NEW URL'

For each Python module, there is only ever one module object.

So if you need to share global state in Python, it's often simplest to just use the global variables within a module.

Modules are the most typical Python singleton

The classic singleton design pattern doesn't always make a lot of sense in Python.

Singletons are most often used for sharing global state. In Python, if you need to share some global state, you can often just use a module object because in Python modules are singletons.

Series: Classes

Classes are a way to bundle functionality and state together. The terms "type" and "class" are interchangeable: list, dict, tuple, int, str, set, and bool are all classes.

You'll certainly use quite a few classes in Python (remember types are classes) but you may not need to create your own often.

To track your progress on this Python Morsels topic trail, sign in or sign up.

0%
A Python Tip Every Week

Need to fill-in gaps in your Python skills? I send weekly emails designed to do just that.