Can I get a reference to a Python property?

get_dict_attr (below) looks up attr in a given object's __dict__, and returns the associated value if its there. If attr is not a key in that __dict__, the object's MRO's __dict__s are searched. If the key is not found, an AttributeError is raised.

def get_dict_attr(obj, attr):
    for obj in [obj] + obj.__class__.mro():
        if attr in obj.__dict__:
            return obj.__dict__[attr]
    raise AttributeError

For example,

class Foo(object):
    x=1
    def bar(self):
        pass
    @property
    def baz(self):
        return 0

foo=Foo()
print(get_dict_attr(foo,'x'))
# 1
print(get_dict_attr(foo,'bar'))
# <unbound method Foo.bar>
print(get_dict_attr(foo,'baz'))
# <property object at 0xb77c0dc4>
print(get_dict_attr(foo,'y'))
# AttributeError

Note that this is very different than the normal rules of attribute lookup. For one thing, data-descriptors in obj.__class__.__dict__ (descriptors with both __get__ and __set__ methods) normally have precedence over values in obj.__dict__. In get_dict_attr, obj.__dict__ has precedence.

get_dict_attr does not try calling __getattr__.

Finally, get_dict_attr will only work with objects obj which are instances of new-style classes.

Nevertheless, I hope it is of some help.


class Foo(object):
    @property
    def bar(self):
        return 0

f = Foo()

This references the property bar:

print(Foo.bar)
# <property object at 0xb76d1d9c>

You see bar is a key in Foo.__dict__:

print(Foo.__dict__['bar'])
# <property object at 0xb775dbbc>

All properties are descriptors, which implies it has a __get__ method:

print(Foo.bar.__get__)
# <method-wrapper '__get__' of property object at 0xb76d7d74>

You can call the method by passing the object f, and the class of f as arguments:

print(Foo.bar.__get__(f,Foo))
# 0

I am fond of the following diagram. Vertical lines show the relationship between an object and the object's class.

When you have this situation:

   Foo                                B
   | Foo.__dict__={'bar':b}           | B.__dict__={'__get__':...}
   |                      \           |      
   f                       `--------> b

f.bar causes b.__get__(f,Foo) to be called.

This is explained in detail here.


Short answer:

Properties return its self when they called from class: MyClass.my_prop

Also, they have fields that contain a link to the actual methods: fget, fset and fdel.

Description:

So, my_class.my_prop (where my_class = MyClass()) returns the value, but MyClass.my_prop returns the property object and MyClass.my_prop.fget returns the getter method of this property. The self is not linked to it, so it should be populated during the call: MyClass.my_prop.fget(my_class)

Example:

class MyClass:
    my_prop = property(lambda self: 'get', lambda self, x: print('set', x))

setter = MyClass.my_prop.fset
getter = MyClass.my_prop.fget

my_class = MyClass()

setter(my_class, 5)     # equals my_class.my_prop = 5
print(getter(my_class)) # equals print(my_class.my_prop)