Python Descriptor as Instance Attribute

Hua Yanghao huayanghao at gmail.com
Thu Jan 19 00:55:21 EST 2012


Hi all,
Currently descriptors only work as class attribute,
and doesn't work as a descriptor when it is an instance attribute.

e.g. if we have descriptor class DescriptorTest,
class Dummy(object):
    d = DescriptorTest()

class Dummy2(object):
    def __init__(self):
        self.d = DescriptorTest()

The instance of Dummy2 does not invoke the descriptor protocols on "d".
Whereas Dummy() instances all share the same descriptor "d".

Yes I know d.__get__() have an "instance" parameter which can be used
to store per-instance values, but sometimes it is just not enough (or it is that
I do not know a better approach exists).

Suppose the below scenario, I want to model a "Register". A register is consist
of some fields, which have different number of bits.
e.g. a 32 bit register divided into 3 field, bit[0] to bit[7] is
called M, bit[8] to bit[15]
is called N, and bit[16] to bit[31] is called Z.
I want to model a register that, when instantiated as "reg", reg.M/N/Z
can directly
reference each field, calling a descriptor protocol to verify and
return the values.

Yes, I know I can use metaclass to create a different class for
different registers,
but that's not seems to be a very smart approach here, as I want all
register instances
be of type "Register". But the default python protocol will not run
descriptor protocols
if a descriptor is an instance attribute. I'm sure I should not be the
only one that facing
this issue and I googled around and found a solution to redefine the
__setattr__ and
__getattribute__ to look up the descriptor protocols first:

107         def __getattribute__(self, name):
108                 value = object.__getattribute__(self, name)
109                 if hasattr(value, '__get__'):
110                         value = value.__get__(self, self.__class__)
111                 return value
112
113         def __setattr__(self, name, value):
114                 try:
115                         obj = object.__getattribute__(self, name)
116                 except AttributeError:
117                         pass
118                 else:
119                         if hasattr(obj, '__set__'):
120                                 return obj.__set__(self, value)
121                 return object.__setattr__(self, name, value)

This works like a charm and each instance of "Register" now invoke the
descriptors properly.

I just do not understand, why such behavior is not a default in python.
Or, is there a better design pattern here?

Thanks & Best Regards,
Hua Yanghao



More information about the Python-list mailing list