wrapt
wrapt copied to clipboard
Descriptors don't seem to work, if they're mixed in
class memoized_property(object):
"""A read-only @property that is only evaluated once."""
def __init__(self, fget, doc=None):
self.fget = fget
self.__doc__ = doc or fget.__doc__
self.__name__ = fget.__name__
def __get__(self, obj, cls):
if obj is None:
return self
obj.__dict__[self.__name__] = result = self.fget(obj)
return result
class B:
@memoized_property
def c(self):
return WeakKeyDictionary()
class Proxy(wrapt.ObjectProxy, B):
pass
if __name__ == '__main__':
b = ProxySon(B())
print(b.c)
print(b.c)
Output:
<WeakKeyDictionary at 0x1109a50d0>
<WeakKeyDictionary at 0x1109a51d0>
!!! not the same
Sorry for slow reply, was on holiday at the time and just catching up.
As far as I can tell your implementation of __get__()
is wrong as you don't check to see whether you already cached the value and return that. Instead you call self.fget()
every time. I would expect something like:
import wrapt
from weakref import WeakKeyDictionary
class memoized_property(object):
"""A read-only @property that is only evaluated once."""
def __init__(self, fget, doc=None):
self.fget = fget
self.__doc__ = doc or fget.__doc__
self.__name__ = fget.__name__
def __get__(self, obj, cls):
if obj is None:
return self
if not self.__name__ in obj.__dict__:
result = obj.__dict__[self.__name__] = self.fget(obj)
else:
result = obj.__dict__[self.__name__]
return result
class B:
@memoized_property
def c(self):
return WeakKeyDictionary()
class Proxy(wrapt.ObjectProxy, B):
pass
if __name__ == '__main__':
b = Proxy(B())
print(b.c)
print(b.c)
It's the implementation taken directly from the SQLAlchemy library. Descriptors are not called if there is an item in __dict___ with the corresponding name - so implementation is perfectly valid.