Descriptors and side effects
Rich Harkins
rich at worldsinfinite.com
Mon Nov 5 12:42:53 EST 2007
Bruno Desthuilliers wrote:
> 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