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