Skip to content

Instantly share code, notes, and snippets.

@mahdi13
Last active December 3, 2017 09:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mahdi13/5cf9243246e63f1ed08b8e26ba6a3604 to your computer and use it in GitHub Desktop.
Save mahdi13/5cf9243246e63f1ed08b8e26ba6a3604 to your computer and use it in GitHub Desktop.
Some kind of transparent proxy to implement `singleton` beautifully
"""
Some kind of transparent proxy to implement `singleton` beautifully.
Thanks to:
* @pylover
* https://github.com/pylover/pymlconf (again @pylover!)
Usage:
>>> # Definition (usually on `global` scope):
>>> my_singleton_object = DeferredObject(MySingletonClass):
>>> # Initialization (usually on application initialization):
>>> my_singleton_object.initialize()
>>> # Usage wherever you want (imagine you are working straight with a `MySingletonClass` object):
>>> my_singleton_object.whatever_you_want_from_your_class()
It is easy, isn't it? :)
"""
class ObjectAlreadyInitializedError(Exception):
pass
class ObjectNotInitializedError(Exception):
pass
class ObjectProxy(object):
"""
A simple object proxy to let deferred object's initialize later (for example: just after import):
This class encapsulates some tricky codes to resolve the proxied object members using the
`__getattribute__` and '__getattr__'. SO TAKE CARE about modifying the code, to prevent
infinite loops and stack-overflow situations.
Module: fancy_module
deferred_object = None # Will be initialized later.
def init():
global deferred_object
deferred_object = AnyValue()
proxy = ObjectProxy(lambda: deferred_object)
In another module:
from fancy_module import proxy, init
def my_very_own_function():
try:
return proxy.any_attr_or_method()
except: ObjectNotInitializedError:
init()
return my_very_own_function()
"""
def __init__(self, resolver):
object.__setattr__(self, '_resolver', resolver)
@property
def proxied_object(self):
o = object.__getattribute__(self, '_resolver')()
# if still is none, raise the exception
if o is None:
raise ObjectNotInitializedError("Client is not initialized yet.")
return o
def __getattr__(self, key):
if key.startswith('_'): # Exclude protected and private methods
return self.__dict__[key]
return getattr(object.__getattribute__(self, 'proxied_object'), key)
def __setattr__(self, key, value):
if key.startswith('_'): # Exclude protected and private methods
self.__dict__[key] = value
return
setattr(object.__getattribute__(self, 'proxied_object'), key, value)
class DeferredObject(ObjectProxy):
_instance = None
def __init__(self, backend_factory):
super(DeferredObject, self).__init__(
self._get_instance
)
self._backend_factory = backend_factory
def _get_instance(self):
return self._instance
def _set_instance(self, v):
self._instance = v
def initialize(self, force=False, **kw):
instance = self._get_instance()
if not force and instance is not None:
raise ObjectAlreadyInitializedError("Object is already initialized.")
self._set_instance(self._backend_factory(**kw))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment