Skip to content

Instantly share code, notes, and snippets.

@jsbueno
Created May 22, 2015 19:37
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 jsbueno/ec7cf147919ecc9f1145 to your computer and use it in GitHub Desktop.
Save jsbueno/ec7cf147919ecc9f1145 to your computer and use it in GitHub Desktop.
a proxy wrapper for objects that lazily creates object copies on simple attribution of the object to other variables.
# copyright Joao S. O. Bueno (2015)
# License: # SVP write me if you intend to reuse stuff here for anything but mayhem
# There is an LGPL with lazyobjects based on this idea for proxy at
# bitbucket.org/jsbueno/metapython [lazy_decorator.py]
# NB: although there is support for inspecting Frames - this works only
# for global variables
# working for Python2 - for python3 onlye the metaclass usage should need to be changed
import gc, types
from copy import copy
from functools import wraps
data_model_methods = """
__repr__ __str__ __cmp__
__hash__ __nonzero__
__delattr__
__call__
__len__ __getitem__ __setitem__ __delitem__ __reversed__ __contains__
__add__ __sub__ __mul__ __floordiv__ __mod__ __divmod__ __pow__ __div__ __truediv__
__lshift__ __rshift__ __and__ __xor__ __or__
__radd__ __rsub__ __rmul__ __rfloordiv__ __rmod__ __rdivmod__
__rpow__ __rdiv__ __rtruediv__
__rlshift__ __rrshift__ __rand__ __rxor__ __ror__
__iadd__ __isub__ __imul__ __ifloordiv__ __imod__ __ipow__ __idiv__ __itruediv__
__ilshift__ __irshift__ __iand__ __ixor__ __ior__
__neg__ __pos__ __abs__ __invert__
__complex__ __int__ __long__ __float__
__oct__ __hex__
__index__ __coerce__
""".split()
def auto_copy_decorator(method):
wraps(method)
instances = {}
def wrapper(self, *args, **kw):
self = self._do_the_thing()
return getattr(self._proxied.__class__, method)(self._proxied, *args, **kw)
return wrapper
class MetaAutoCopyProxy(type):
def __new__(metacls, name, bases, dct):
for key in data_model_methods:
dct[key] = auto_copy_decorator(key)
return type.__new__(metacls, name, bases, dct)
class AutoCopyProxy(object):
__metaclass__ = MetaAutoCopyProxy
def __init__(self, proxied):
self._proxied = proxied
self._instances = {}
def _do_the_thing(self):
first_copy = True
new_self = self
for ref in gc.get_referrers(self):
if isinstance(ref, types.FrameType):
ref = ref.f_locals
elif isinstance(ref, dict):
pass
else:
continue
for key, value in ref.items():
if value is self:
if first_copy:
first_copy = False
continue
new_self = AutoCopyProxy(copy(self._proxied))
# Changeling thing:
ref[key] = new_self
return new_self
def __getattribute__(self, attr):
if attr not in ("__init__", "_instances", "_proxied", "_do_the_thing"):
self = self._do_the_thing()
return getattr(self._proxied, attr)
return object.__getattribute__(self, attr)
"""
>>> from autocopyproxy import AutoCopyProxy as A
>>> x = A([])
>>> y = x
>>> y is x
True
>>> y.append(5)
>>> x
[]
>>> y
[5]
>>> y is x
False
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment