Singleton - это порождающий шаблон проектирования, который гарантирует, что у класса есть только один экземпляр, и предоставляет глобальную точку доступа к этому экземпляру.
class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super().__new__(cls, *args, **kwargs)
return cls._instance
Объяснение:
__new__
, который отвечает за создание экземпляра_instance
super().__new__()
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class Database:
def __init__(self, connection_url):
self.connection_url = connection_url
Преимущества:
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 Logger(metaclass=SingletonMeta):
def __init__(self, log_file):
self.log_file = log_file
Когда использовать:
В Python модули по своей природе являются singleton:
# config.py
class Config:
def __init__(self):
self.settings = {}
config = Config()
# В другом файле
from config import config # Всегда будет один и тот же экземпляр
Плюсы:
Для многопоточных приложений нужно добавить блокировку:
from threading import Lock
class ThreadSafeSingleton:
_instance = None
_lock = Lock()
def __new__(cls):
with cls._lock:
if not cls._instance:
cls._instance = super().__new__(cls)
return cls._instance
Выбор реализации зависит от конкретных требований:
Лучшей практикой считается избегать Singleton там, где можно обойтись dependency injection, но когда он действительно нужен, Python предоставляет несколько элегантных способов его реализации.