python attribute lookup without any descriptor magic?

descriptor, python, python-datamodel

Solution

Most descriptors do their job when accessed as instance attribute only. So it's convenient to return itself when it's accessed for class:

class FixedValueProperty(object):
    def __init__(self, value):
        self.value = value
    def __get__(self, inst, cls):
        if inst is None:
            return self
        return self.value

This allows you to get descriptor itself:

>>> class C(object):
...     prop = FixedValueProperty('abc')
... 
>>> o = C()
>>> o.prop
'abc'
>>> C.prop
<__main__.FixedValueProperty object at 0xb7eb290c>
>>> C.prop.value
'abc'
>>> type(o).prop.value
'abc'

Note, that this works for (most?) built-in descriptors too:

>>> class C(object):
...     @property
...     def prop(self):
...         return 'abc'
... 
>>> C.prop
<property object at 0xb7eb0b6c>
>>> C.prop.fget
<function prop at 0xb7ea36f4>

Accessing descriptor could be useful when you need to extent it in subclass, but there is a better way to do this.

Problem

I've started to use the python descriptor protocol more extensively in the code I've been writing. Typically, the default python lookup magic is what I want to happen, but sometimes I'm finding I want to get the descriptor object itself instead the results of its `__get__` method. Wanting to know the type of the descriptor, or access state stored in the descriptor, or somesuch thing. I wrote the code below to walk the namespaces in what I believe is the correct ordering, and return the attribute raw regardless of whether it is a descriptor or not. I'm surprised though that I can't find a built-in function or something in the standard library to do this -- I figure it has to be there and I just haven't noticed it or googled for the right search term. Is there functionality somewhere in the python distribution that already does this (or something similar)? Thanks! ``` from inspect import isdatadescriptor def namespaces(obj): obj_dict = None if hasattr(obj, '__dict__'): obj_dict = object.__getattribute__(obj, '__dict__') obj_class = type(obj) return obj_dict, [t.__dict__ for t in obj_class.__mro__] def getattr_raw(obj, name): # get an attribute in the same resolution order one would normally, # but do not call __get__ on the attribute even if it has one obj_dict, class_dicts = namespaces(obj) # look for a data descriptor in class hierarchy; it takes priority over # the obj's dict if it exists for d in class_dicts: if name in d and isdatadescriptor(d[name]): return d[name] # look for the attribute in the object's dictionary if obj_dict and name in obj_dict: return obj_dict[name] # look for the attribute anywhere in the class hierarchy for d in class_dicts: if name in d: return d[name] raise AttributeError ``` Edit Wed, Oct 28, 2009. Denis's answer gave me a convention to use in my descriptor classes to get the descriptor objects themselves. But, I had an entire class hierarchy of descriptor classes, and I didn't want to begin every `__get__` function with a boilerplate ``` def __get__(self, instance, instance_type): if instance is None: return self ... ``` To avoid this, I made the root of the descriptor class tree inherit from the following: ``` def decorate_get(original_get): def decorated_get(self, instance, instance_type): if instance is None: return self return original_get(self, instance, instance_type) return decorated_get class InstanceOnlyDescriptor(object): """All __get__ functions are automatically wrapped with a decorator which causes them to only be applied to instances. If __get__ is called on a class, the decorator returns the descriptor itself, and the decorated __get__ is not called. """ class __metaclass__(type): def __new__(cls, name, bases, attrs): if '__get__' in attrs: attrs['__get__'] = decorate_get(attrs['__get__']) return type.__new__(cls, name, bases, attrs) ```

Original source