Skip to content

Instantly share code, notes, and snippets.

@tchar
Created July 23, 2021 14:25
Show Gist options
  • Save tchar/2f8b34377c9feee70025fab3fba84c05 to your computer and use it in GitHub Desktop.
Save tchar/2f8b34377c9feee70025fab3fba84c05 to your computer and use it in GitHub Desktop.
Singleton pattern, singletonmethod decorator
from typing import Any, Callable, Type
from functools import wraps
class Singleton(type):
_instances = {}
def __call__(cls: Type[Any], *args: Any, **kwargs: Any) -> Any:
'''Gets as input the class and args/kwargs and returns either an already
instantiated object or a new object from that class'''
if cls not in cls._instances:
cls._instances[cls] = super(
Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonMethod:
def __init__(self, func: Callable[[Any], Any]):
self._func = func
def __get__(self, obj: Any, cls: Type[Any]):
'''Returns a wrapper which passes the self to the function provided
If obj is None (meaning it is a class method) instantiates the class
and passes it as the self argument'''
@wraps(self._func)
def _wrapper(*args, **kwargs):
if obj is None:
_self = cls()
else:
_self = obj
return self._func(_self, *args, **kwargs)
return _wrapper
def singletonmethod(func):
'''Returns a SingletonMethod object'''
return SingletonMethod(func)
def main():
class Test(metaclass=Singleton):
def __init__(self, value=0):
self.value = value
@singletonmethod
def f(self, value: int) -> str:
'''Some singletonmethod docstring'''
return 'My value: {}, Your value: {}'.format(self.value, value)
# Can be called without instantiation
tf = Test.f(2)
assert tf == 'My value: 0, Your value: 2'
# Can be called with instantiation but still holds the previous reference
tf = Test(1).f(1)
assert tf == 'My value: 0, Your value: 1'
assert Test.f.__doc__ == 'Some singletonmethod docstring'
assert Test().f.__doc__ == 'Some singletonmethod docstring'
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment