singlepy

Small library that offers two simple to use singleton-pattern metaclasses: Singleton and WeakSingleton


Keywords
singleton, python
License
MIT
Install
pip install singlepy==1.0.1

Documentation

singlepy

Build Status Coverage Status

Small library that offers two simple to use singleton-pattern metaclasses:

  • Singleton
  • WeakSingleton

Install it using pip: pip install singlepy

Singleton

Makes usage of the arguments passed to the class constructor to identify each unique instance of the class. All instances, once created, will live until the end of the program.

Example

In [1]: from singlepy import Singleton

In [2]: class Number(metaclass=Singleton):
   ...:     def __init__(self, value):
   ...:         self.value = value
   ...:

In [3]: id(Number(1)) == id(Number(1))
Out[3]: True

In [4]: id(Number(1)) == id(Number(2))
Out[4]: False

In [5]: id(Number(2)) == id(Number(2))
Out[5]: True

WeakSingleton

Makes usage of the arguments passed to the class constructor to identify each unique instance of the class. Individual instances will be destroyed if there are no references to it.

Example

In [1]: from singlepy import WeakSingleton

In [2]: class Number(metaclass=WeakSingleton):
   ...:     def __init__(self, value):
   ...:         self.value = value
   ...:

In [3]: one = Number(1)

In [4]: id(one) == id(Number(1))
Out[4]: True

In [5]: two = Number(2)

In [6]: id(one) != id(two)
Out[6]: True

In [7]: id_one = id(one)

In [8]: del one

In [9]: id_two = id(two)

In [10]: two_two = Number(2)

In [11]: two_two is two
Out[11]: True

In [12]: del two

In [13]: two_two is Number(2)
Out[13]: True

In [14]: del two_two

In [15]: id_one == Number(1)
Out[15]: False

In [16]: id_two == Number(2)
Out[16]: False

Custom singleton key

Imagine you have a class called Numbers, that stores a list of numbers:

In [1]: class Numbers:
   ...:     def __init__(self, numbers):
   ...:         self._numbers = numbers
   ...:
   ...:     def sum(self):
   ...:         return sum(self._numbers)
   ...:
   ...:     def min(self):
   ...:         return min(self._numbers)
   ...:
   ...:     def max(self):
   ...:         return max(self._numbers)
   ...:

In [2]: Numbers([1, 2, 3, 4])
Out[2]: <__main__.Numbers at 0x10dfd5400>

And you want this class to be a singleton for the given set of numbers, no matter the order. The classes Singleton and WeakSingleton offer a way to do this through _make_singleton_key:

In [1]: from singlepy import Singleton
   ...: class Numbers(metaclass=Singleton):
   ...:     @staticmethod
   ...:     def _make_singleton_key(numbers):
   ...:         return str(list(sorted(numbers)))
   ...:
   ...:     ...

In [2]: id(Numbers([2, 3, 1, 4]))
Out[2]: 4535905696

In [3]: id(Numbers([1, 2, 3, 4]))
Out[3]: 4535905696

In [4]: id(Numbers([1, 2, 3]))
Out[4]: 4535654272

Important: _make_singleton_key must be a staticmethod and its return value must be hashable.