|
12 | 12 | import traceback |
13 | 13 | import warnings |
14 | 14 | from datetime import datetime, timedelta, timezone |
| 15 | +from threading import Lock |
15 | 16 |
|
16 | 17 |
|
17 | 18 | class Failure: |
@@ -230,3 +231,35 @@ def split_unescape(s, delim, escape="\\", unescape=True): |
230 | 231 | current.append(ch) |
231 | 232 | ret.append("".join(current)) |
232 | 233 | return ret |
| 234 | + |
| 235 | + |
| 236 | +class Singleton(type): |
| 237 | + """ |
| 238 | + Metaclass for singleton classes. To create a singleton class use this metaclass: |
| 239 | +
|
| 240 | + class MySingletonClass(metaclass=Singleton): |
| 241 | + pass |
| 242 | +
|
| 243 | + Now Singleton will ensure that only one instance of MySingletonClass is created. |
| 244 | + """ |
| 245 | + |
| 246 | + _instances = {} |
| 247 | + _lock = Lock() |
| 248 | + |
| 249 | + def __call__(cls, *args, **kwargs): |
| 250 | + """ |
| 251 | + Called when you create a new instance of a class with this metaclass. |
| 252 | +
|
| 253 | + It ensures that only one instance of the class is created (singleton pattern). |
| 254 | +
|
| 255 | + When you call `MySingletonClass(args, kwargs)`, python calls |
| 256 | + `Singleton.__call__(MySingletonClass, args, kwargs)`. |
| 257 | +
|
| 258 | + This method in turn check if an instance of `MySingletonClass` already exists. |
| 259 | + If not, it creates one and stores it in the `_instances` dictionary. |
| 260 | + """ |
| 261 | + if cls not in cls._instances: # Only grab the lock if the instance is not in the dict |
| 262 | + with cls._lock: # Ensure thread-safety |
| 263 | + if cls not in cls._instances: # in case instance was added while waiting for lock |
| 264 | + cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) |
| 265 | + return cls._instances[cls] |
0 commit comments