forked from sympy/sympy
-
Notifications
You must be signed in to change notification settings - Fork 1
/
singleton.py
77 lines (58 loc) · 2.08 KB
/
singleton.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
"""Singleton mechanism"""
from core import Registry
from assumptions import ManagedProperties
from sympify import sympify
class SingletonRegistry(Registry):
"""
A map between singleton classes and the corresponding instances.
E.g. S.Exp == C.Exp()
"""
__slots__ = []
__call__ = staticmethod(sympify)
def __repr__(self):
return "S"
S = SingletonRegistry()
class Singleton(ManagedProperties):
"""
Metaclass for singleton classes.
A singleton class has only one instance which is returned every time the
class is instantiated. Additionally, this instance can be accessed through
the global registry object S as S.<class_name>.
Examples
========
>>> from sympy import S, Basic
>>> from sympy.core.singleton import Singleton
>>> class MySingleton(Basic):
... __metaclass__ = Singleton
>>> Basic() is Basic()
False
>>> MySingleton() is MySingleton()
True
>>> S.MySingleton is MySingleton()
True
** Developer notes **
The class is instanciated immediately at the point where it is defined
by calling cls.__new__(cls). This instance is cached and cls.__new__ is
rebound to return it directly.
The original constructor is also cached to allow subclasses to access it
and have their own instance.
"""
def __init__(cls, name, bases, dict_):
super(Singleton, cls).__init__(cls, name, bases, dict_)
for ancestor in cls.mro():
if '__new__' in ancestor.__dict__:
break
if isinstance(ancestor, Singleton) and ancestor is not cls:
ctor = ancestor._new_instance
else:
ctor = cls.__new__
cls._new_instance = staticmethod(ctor)
the_instance = ctor(cls)
def __new__(cls):
return the_instance
cls.__new__ = staticmethod(__new__)
setattr(S, name, the_instance)
# Inject pickling support.
def __getnewargs__(self):
return ()
cls.__getnewargs__ = __getnewargs__