Python > Object-Oriented Programming (OOP) in Python > Metaclasses > Custom Metaclasses
Custom Metaclass to Implement a Singleton Pattern
This example demonstrates how to use a custom metaclass to implement the Singleton pattern in Python. The Singleton pattern ensures that only one instance of a class is ever created.
Understanding the Singleton Pattern
The Singleton pattern is a creational design pattern that restricts the instantiation of a class to one object. It's useful when exactly one object is needed to coordinate actions across the system. A metaclass is a good way to enforce this at the class definition level.
Code Implementation
The SingletonMeta
metaclass overrides the __call__
method. When a class with this metaclass is 'called' (i.e., when you try to create an instance), the __call__
method is executed. It checks if an instance of the class already exists in the _instances
dictionary. If not, it creates a new instance using super().__call__(*args, **kwargs)
and stores it in the dictionary. Subsequent calls to the class will return the existing instance from the dictionary. This ensures that only one instance of the Singleton
class is ever created. Notice that the value attribute is only set on the first instantiation.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
def __init__(self, value):
self.value = value
# Both instances will point to the same object
instance1 = Singleton(10)
instance2 = Singleton(20)
print(instance1.value) # Output: 10
print(instance2.value) # Output: 10
print(instance1 is instance2) # Output: True
Real-Life Use Case: Database Connection
A common use case for the Singleton pattern is managing a database connection. You typically only want one connection to the database to avoid resource contention and ensure data consistency. A Singleton metaclass can ensure that only one database connection object is created.
Best Practices
Interview Tip
Be prepared to discuss the Singleton pattern and its potential drawbacks. Common criticisms include that it can hide dependencies, make testing more difficult, and violate the single responsibility principle.
When to Use Them
Use the Singleton pattern when you need to ensure that only one instance of a class exists and that there is a global point of access to that instance. Consider alternatives if the benefits don't outweigh the potential drawbacks.
Memory footprint
The Singleton pattern generally has a low memory footprint. It only holds a single instance of the class in memory.
Alternatives
Pros
Cons
FAQ
-
Is the Singleton pattern always the best solution?
No, the Singleton pattern has drawbacks and should be used judiciously. Consider alternatives like dependency injection before resorting to a Singleton. -
How can I make a Singleton thread-safe?
Use locking mechanisms, such as a mutex, to protect the creation of the instance in a multithreaded environment. The locking should occur within the __call__ method of the metaclass.