Dynamic use of property() fails
Bruno Desthuilliers
bruno.42.desthuilliers at websiteburo.invalid
Tue Apr 15 05:19:48 EDT 2008
andrew cooke a écrit :
> On Apr 15, 4:06 am, Bruno Desthuilliers <bruno.
> 42.desthuilli... at websiteburo.invalid> wrote:
>
>> The canonical solution is to use a custom descriptor instead of a property:
(snip code)
> i tried code very similar after reading the first replies and found
> that it did not work as expected on setting. for example, in
>
> person = Person()
> person.age = 27
>
> "age" is set in the instance's dictionary (as 27; the descriptor is
> not called), which then shadows the definition of age in the class
> dictionary.
Are you sure your Person class is a new-style one (inheriting, directly
or not, from object) ? The descriptor protocol doesn't work properly on
old-style classes, with *exactly* the symptom you describe here (setter
is not invoked, property get shadowed by an instance attribute)
> my understanding was that the descriptor is only called in the class
> context,
The descriptor protocol is only invoked on class attributes.
> so would be called if, say, a subclass tried to redefine
> age. but maybe i am still confused.
Possibly.
> i am about to go to sleep. i guess i will try your code exactly
> tomorrow, but it looks very close to mine which showed this problem.
> are you sure your solution works?
Yes - minus a couple (unrelated) typos ('name' instead of 'self.name' in
Field.__set__, and 'self._values = []' instead of 'self._values = {}' in
ActiveDAO.__init__). Here's the corrected one:
class Field(object):
def __init__(self, name, onchange):
self.name = name
self.onchange = onchange
def __get__(self, instance, cls):
if instance is None:
# called on the class
return self
# called on instance
return instance._values[self.name]
def __set__(self, instance, value):
instance._values[self.name] = self.onchange(value)
class ActiveDAO(object):
def __init__(self):
self._values = {}
class Person(ActiveDAO):
name = Field('name', lambda v: v.strip().capitalize())
age = Field('age', lambda v : int(v))
More information about the Python-list
mailing list