Descriptors and side effects
Bruno Desthuilliers
bruno.42.desthuilliers at wtf.websiteburo.oops.com
Mon Nov 5 11:28:13 EST 2007
Rich Harkins a écrit :
> mrkafk at gmail.com wrote:
>> Hello everyone,
>>
>> I'm trying to do seemingly trivial thing with descriptors: have
>> another attribute updated on dot access in object defined using
>> descriptors.
>
> [snip]
>
>> A setter function should have updated self.l just like it updated
>> self.s:
>>
>> def __set__(self, obj, val):
>> self.s=val
>> self.l=len(val)
>> print "setting value:", self.s, "length:", self.l
>>
>> Yet it didn't happen.
>>
> [snip]
>
> I noticed that Python will block all attribute overrides (either via
> __dict__ through setattr) if the property has a __set__ method.
It doesn't "block", it controls access to... Of course, if the __set__
method is a no-op, then nothing will happen.
> The
> standard property has this method and there is no way that I can find to
> defeat it.
"defeat" ? Why don't you just pass the appropriate fset function to
property ?
> So, here is what I use:
>
> class ConstProperty(object):
> """
> Provides a property that keeps its return value. The function will
> only be called on the first access. After that the same value can
> be used over and over again with no function call penalty. If the
> cached value needs to be cleared, simply del the attribute.
>
> >>> class MyClass(object):
> ... def __init__(self, x):
> ... self.x = x
> ... @ConstProperty
> ... def y(self):
> ... print "HERE"
> ... return self.x ** 2
> ...
> >>> obj = MyClass(5)
> >>> obj.y
> HERE
> 25
> >>> obj.y
> 25
> """
>
> def __init__(self, fn):
> self.fn = fn
>
> def __get__(self, target, cls=None):
> if target is None:
> return self.fn # Helps pydoc
> else:
> obj = self.fn(target)
> setattr(target, self.fn.__name__, obj)
> return obj
>>> m = MyClass(5)
>>> m.__dict__
{'x': 5}
>>> m.y
HERE
25
>>> m.__dict__
{'y': 25, 'x': 5}
>>> m.x = 42
>>> m.y
25
>>> m.__dict__
{'y': 25, 'x': 42}
>>>
I'm sorry, but this looks like a very complicated way to do a simple thing:
class MySimpleClass(object):
def __init__(self, x):
self.x = x
self.y = x ** 2
More information about the Python-list
mailing list