Can I get a reference to a Python property?
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)
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.