Skip to content

Instantly share code, notes, and snippets.

@qexat
Created December 6, 2023 20:31
Show Gist options
  • Select an option

  • Save qexat/a61b255b2e55de525acf81d7905b54ae to your computer and use it in GitHub Desktop.

Select an option

Save qexat/a61b255b2e55de525acf81d7905b54ae to your computer and use it in GitHub Desktop.
cursed singleton in pure python
from __future__ import annotations
import os
import typing
_ALREADY_EXISTS = "cannot instantiate singleton class {!r}: the instance already exists"
class SingletonMeta(type):
"""
Metaclass of which classes can only be instantiated once.
The exception is raised at runtime ; it cannot be caught statically.
"""
# Tracks whether an instance of SingletonMeta's classes exists or not
_has_instance: dict[typing.Self, bool] = {}
def _remove_destroyed_instance(self) -> None:
self.__class__._has_instance[self] = False
@staticmethod
def _del_substitute(cls_inst: typing.Any) -> None:
cls_inst.__class__._remove_destroyed_instance()
def __new__(cls, *args: typing.Any, **kwargs: typing.Any) -> typing.Self:
instance: SingletonMeta = super().__new__(cls, *args, **kwargs)
# adds the newly-created class in our tracking dict
cls._has_instance[instance] = False
setattr(instance, "__del__", cls._del_substitute)
return instance
# __call__(self: SingletonMeta[Cls], *args, **kwargs) -> Cls
def __call__(self, *args: typing.Any, **kwargs: typing.Any):
if self.__class__._has_instance[self]:
# instance already exists! we don't allow that :)
raise TypeError(_ALREADY_EXISTS.format(self.__name__))
# we create the instance BEFORE registering it: we have to be sure
# that no exception was raised during the process
instance = super().__call__(*args, **kwargs)
self.__class__._has_instance[self] = True
# send it back to the normal (sane) circuitry lol
return instance
class MyClass(metaclass=SingletonMeta):
def __init__(self, value: int) -> None:
self.value = value
def __repr__(self) -> str:
return f"{self.__class__.__name__}(value: {self.value})"
def main() -> int:
print(MyClass(-1)) # ok
# the instance gets deleted (not guaranteed, though)
inst1 = MyClass(3) # ok (usually)
print(inst1)
inst2 = MyClass(5) # error: TypeError: cannot instantiate singleton cl...
print(inst2)
return os.EX_OK
if __name__ == "__main__":
raise SystemExit(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment