8.1. Singleton¶
EN: Singleton
PL: Singleton
Type: object
8.1.1. Pattern¶
To ensure a class has a single instance
Database connection pool
HTTP Gateway
Settings
Main game/program window

8.1.2. Problem¶

from typing import Any
class ConfigManager:
settings: dict[str, Any]
def __init__(self) -> None:
self.settings = {}
def set(self, key: str, value: Any) -> None:
self.settings[key] = value
def get(self, key: str) -> Any:
return self.settings.pop(key)
if __name__ == '__main__':
manager = ConfigManager()
manager.set('name', 'Mark')
other = ConfigManager()
print(other.get('name'))
# Traceback (most recent call last):
# KeyError: 'name'
8.1.3. Solution¶

from __future__ import annotations
from typing import Any
class ConfigManager:
settings: dict[str, Any]
instance: ConfigManager | None = None
def __init__(self) -> None:
self.settings = {}
@classmethod
def get_instance(cls) -> ConfigManager:
if not cls.instance:
cls.instance = super().__new__(cls)
cls.instance.__init__()
return cls.instance
def set(self, key: str, value: Any) -> None:
self.settings[key] = value
def get(self, key: str) -> Any:
return self.settings.pop(key)
if __name__ == '__main__':
manager = ConfigManager.get_instance()
manager.set('name', 'Mark')
other = ConfigManager.get_instance()
print(other.get('name'))
# Mark
8.1.4. Use Case - 0x01¶
from typing import Self
class Database:
connection: Self | None = None
@classmethod
def connect(cls):
if not cls.connection:
cls.connection = ... # connect to database
return cls.connection
db1 = Database.connect()
db2 = Database.connect()
db1 is db2
# True
8.1.5. Use Case - 0x02¶
from typing import Self
class Singleton:
instance: Self | None = None
def __new__(cls, *args, **kwargs):
if cls.instance is None:
cls.instance = object.__new__(cls)
cls.instance.__init__(*args, **kwargs)
return cls.instance
class Database(Singleton):
pass
db1 = Database()
db2 = Database()
db1 is db2
# True
8.1.6. Use Case - 0x03¶
class Singleton(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 Database(metaclass=Singleton):
pass
class Settings(metaclass=Singleton):
pass
db1 = Database()
db2 = Database()
db1 is db2
# True
8.1.7. Assignments¶
"""
* Assignment: DesignPatterns Creational SingletonSettings
* Complexity: easy
* Lines of code: 7 lines
* Time: 5 min
English:
1. Create singleton class `Settings`
2. Use `get_instance()` classmethod
3. Run doctests - all must succeed
Polish:
TODO: Polish translation
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from pprint import pprint
>>> result_a = Settings.get_instance()
>>> result_b = Settings.get_instance()
>>> result_a is result_b
True
"""
from typing import Self
class Settings:
pass
"""
* Assignment: DesignPatterns Creational SingletonDatabaseConnection
* Complexity: easy
* Lines of code: 7 lines
* Time: 5 min
English:
1. Create singleton class `Database`
2. Use `connect()` classmethod
3. Run doctests - all must succeed
Polish:
TODO: Polish translation
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from pprint import pprint
>>> result_a = Database.connect()
>>> result_b = Database.connect()
>>> result_a is result_b
True
"""
from typing import Self
class Database:
pass
"""
* Assignment: DesignPatterns Creational SingletonQueue
* Complexity: medium
* Lines of code: 7 lines
* Time: 5 min
English:
1. Create singleton class `Singleton`
2. Use `__new__()` object constructor
3. Run doctests - all must succeed
Polish:
TODO: Polish translation
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from pprint import pprint
>>> class Queue(Singleton):
... pass
>>> result_a = Queue()
>>> result_b = Queue()
>>> result_a is result_b
True
"""
from typing import Self
class Singleton:
pass
"""
* Assignment: DesignPatterns Creational SingletonLogger
* Complexity: medium
* Lines of code: 7 lines
* Time: 5 min
English:
1. Create singleton class `Singleton`
2. Use `Metaclass`
3. Run doctests - all must succeed
Polish:
TODO: Polish translation
Tests:
>>> import sys; sys.tracebacklimit = 0
>>> from pprint import pprint
>>> class Logger(metaclass=Singleton):
... pass
>>> result_a = Logger()
>>> result_b = Logger()
>>> result_a is result_b
True
"""
from typing import Self
class Singleton(type):
pass