Skip to content

Instantly share code, notes, and snippets.

@pymen
Created January 13, 2022 15:06
Show Gist options
  • Save pymen/0e8794a7ee2f051ef01f058ef0c13d3d to your computer and use it in GitHub Desktop.
Save pymen/0e8794a7ee2f051ef01f058ef0c13d3d to your computer and use it in GitHub Desktop.

Revisions

  1. pymen created this gist Jan 13, 2022.
    64 changes: 64 additions & 0 deletions LazyObject
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,64 @@
    import operator

    class LazyObject:

    _wrapped = None
    _is_init = False

    def __init__(self, factory, **factory_kwargs):
    # Assign using __dict__ to avoid the setattr method.
    self.__dict__['_factory'] = factory
    self.__dict__['_kwargs'] = factory_kwargs

    def _setup(self):
    self._wrapped = self._factory(**self._kwargs)
    self._is_init = True

    def new_method_proxy(func):
    """
    Util function to help us route functions
    to the nested object.
    """

    def inner(self, *args):
    if not self._is_init:
    self._setup()
    return func(self._wrapped, *args)

    return inner

    def __setattr__(self, name, value):
    # These are special names that are on the LazyObject.
    # every other attribute should be on the wrapped object.
    if name in {"_is_init", "_wrapped"}:
    self.__dict__[name] = value
    else:
    if not self._is_init:
    self._setup()
    setattr(self._wrapped, name, value)

    def __delattr__(self, name):
    if name == "_wrapped":
    raise TypeError("can't delete _wrapped.")
    if not self._is_init:
    self._setup()
    delattr(self._wrapped, name)

    __getattr__ = new_method_proxy(getattr)
    __bytes__ = new_method_proxy(bytes)
    __str__ = new_method_proxy(str)
    __bool__ = new_method_proxy(bool)
    __dir__ = new_method_proxy(dir)
    __hash__ = new_method_proxy(hash)
    __class__ = property(new_method_proxy(operator.attrgetter("__class__")))
    __eq__ = new_method_proxy(operator.eq)
    __lt__ = new_method_proxy(operator.lt)
    __gt__ = new_method_proxy(operator.gt)
    __ne__ = new_method_proxy(operator.ne)
    __hash__ = new_method_proxy(hash)
    __getitem__ = new_method_proxy(operator.getitem)
    __setitem__ = new_method_proxy(operator.setitem)
    __delitem__ = new_method_proxy(operator.delitem)
    __iter__ = new_method_proxy(iter)
    __len__ = new_method_proxy(len)
    __contains__ = new_method_proxy(operator.contains)