To the question:
Why can\'t descriptors be instance attributes?
it has been answered that:
descriptor obj
Plenty of advanced functionality only works when defined on a class rather than an instance; all of the special methods, for example. As well as making code evaluation more efficient, this makes clear the separation between instances and types which otherwise would tend to collapse (because of course all types are objects).
I'm not sure how recommended this is, but you could in the instance store a mapping from descriptor instance to attribute value:
class Prop(object):
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj._value * obj._multiplier[self]
def __set__(self, obj, value):
if obj is None:
return self
obj._value = value
class Obj(object):
val = Prop()
def __init__(self):
self._value = 1
self._multiplier = {Obj.val: 0}
This has obvious advantages over the other two suggested options:
__getattribute__
is inefficient (as all attribute access must go through the overridden special method) and is fragile.As an alternative, you could use a proxy property:
class PerInstancePropertyProxy(object):
def __init__(self, prop):
self.prop = prop
def __get__(self, instance, owner):
if instance is None:
return self
return instance.__dict__[self.prop].__get__(instance, owner)
def __set__(self, instance, value):
instance.__dict__[self.prop].__set__(instance, value)
class Prop(object):
def __init__(self, value, multiplier):
self.value = value
self.multiplier = multiplier
def __get__(self, instance, owner):
if instance is None:
return self
return self.value * self.multiplier
def __set__(self, instance, value):
self.value = value
class Obj(object):
val = PerInstancePropertyProxy('val')
def __init__(self):
self.__dict__['val'] = Prop(1.0, 10.0)
def prop(self, attr_name):
return self.__dict__[attr_name]