#import functools
#__all__ = ['cached_property']
import functools
config = {"caching": True, 'verbose': False}
[docs]def cached_property(*hashlist):
class CachedProperty(object):
def __init__(self, fget=None):
#super(CachedProperty, self).__init__(fget)
self.function = fget
self.hashlist = hashlist
self.cache = None
self.thahash = None
functools.update_wrapper(self, fget)
def __get__(self, parentclass, _none=None):
#__doc__ = self.__doc__
if not config["caching"]:
#return super(CachedProperty, self).__get__(parentclass)
return self.function(parentclass)
else:
dahash = hash_attributes(parentclass, self.hashlist)
# Return cached or recalc if hashes differ
if not self.cache is None and dahash == self.thahash:
return self.cache
else:
self.thahash = dahash
#res = super(CachedProperty, self).__get__(parentclass)
res = self.function(parentclass)
self.cache = res
return res
# CachedProperty = property # ENABLE FOR SPHINX-APIDOC
return CachedProperty
[docs]def rec_getattr(obj, attr):
if attr == "self":
return obj
elif '.' not in attr:
return getattr(obj, attr)
else:
l = attr.split('.')
return rec_getattr(getattr(obj, l[0]), '.'.join(l[1:]))
[docs]def c_mul(a, b):
"""
C type multiplication
http://stackoverflow.com/questions/6008026/how-hash-is-implemented-in-python-3-2
"""
return eval(hex((int(a) * b) & 0xFFFFFFFF)[:-1])
[docs]def hash_attributes(class_instance, hashlist):
"""
http://effbot.org/zone/python-hash.htm
"""
value = 0x345678
for attribute in hashlist:
el = rec_getattr(class_instance, attribute)
# hash
try:
thahash = hash(el)
except TypeError: # Lists
if config['verbose']:
print("bad cache: "+str(class_instance.__name__)+" attribute: "+attribute)
try:
thahash = hash(frozenset(el))
except TypeError:
thahash = hash(str(el))
value = c_mul(1000003, value) ^ thahash
value = value ^ len(hashlist)
if value == -1:
value = -2
return value
[docs]class HashedObject(object):
"""
Provide a list of attributes to hash down for tracking changes
"""
hashlist = ()
def __hash__(self):
return hash_attributes(self, self.hashlist)
[docs]class test(object):
def __init__(self):
self.num = 3
@cached_property('num')
def neu(self):
print("tuwas")
return self.num
#@neu.reset
#def reset(self):
# pass
#recalc = cache.reset
#global config
#print(config)
#ab = test()
#print("jojo")
#print(ab.neu)
#print(ab.neu)