Determine if given class attribute is a property or not, Python object

Question:

It’s all in the title. Here is the following example:

class A(object):
    my_var = 5

    def my_method(self, drink='beer'):
        return 'I like %s' % drink

    @property
    def my_property(self):
        return 'I do not drink coffee'

I instantiate an A object and I want to know the type of each attribute and if it is a callable. For this I’m using dir().

obj = A()

for attr in dir(obj):
    print 'Type: %s' % type(obj)
    print 'Is callable: %s' % callable(attr)

I have to know also if an attribute is a property. I’m sure that there is a way to know this.
All suggestions will be appreciated.

Asked By: ScotchAndSoda

||

Answers:

I once asked a similar question. The trouble you’ll run into, of course, is that you can’t access the property through the instance to determine its type without calling the getter, which gets you the type of whatever the getter returns. So you have to access the property through its class rather than through the instance.

property is already a type, so you can just compare directly to that. (I originally had some superfluous code here that got the property type out of a class that had a property. I thought this was necessary due to a typo when I was testing things.)

obj_type = type(obj)

for attr in dir(obj):
    if isinstance(getattr(type(obj), attr, None), property):
        print attr, "is a property"

Don’t worry about having an instance attribute with the same name. It’s ignored in attribute lookup if there’s a data descriptor of the same name on the class (property is a data descriptor).

Of course, any class can be a data descriptor, not just property, so in theory you really want to check for __get__() and/or __set__() and/or __delete__() attributes on the type. But the problem with that approach is that all functions and methods are themselves descriptors and therefore would be caught by that check. It quickly becomes silly to try to find all the exceptions.

Answered By: kindall

You need to look at the class (this is the case for descriptors in general), which for objects you can find via the __class__ attribute or by using the type function:

>>> obj.__class__.my_property
<property object at 0xb74bd16c>

or by

>>> type(obj).my_property
<property object at 0xb720b93c>

These result in the same “property object” as if you were to directly check the attribute of the class (implying you know the class’ name in your code instead of checking it dynamically like you probably should rather do):

>>> A.my_property
<property object at 0xb7312345>

So to test if a specific attribute of an object is a property, this would be one solution:

>>> isinstance(type(obj).my_property, property)
True
Answered By: John La Rooy

To add to the John La Rooy’s answer (and bugmenot123’s comment), it’s easy to extend the code to check for arbirary attribute names.


Let’s define a class with a property, and its instance:

class MyClass:
    not_a_property = None
    @property
    def my_property(self):
            pass
    def my_method(self):
            pass

my_object = MyClass()

We can simply use any getattr with an arbitrary string to check if the attribute of the class of the given object is a property, just like John La Rooy demonstrated:

>>> isinstance(getattr(type(my_object), 'not_a_property'), property)
False
>>> isinstance(getattr(type(my_object), 'my_property'), property)
True
>>> isinstance(getattr(type(my_object), 'my_method'), property)
False

To get for all property method names of an object, you can loop through dir of the class, like this:

for attr in dir(type(my_object)):
    print(
            f'{attr} is a property method:'.ljust(42),
            isinstance(getattr(type(my_object), attr), property)
    )

The loop above prints the following output:

__class__ is a property method:            False
__delattr__ is a property method:          False
__dict__ is a property method:             False
__dir__ is a property method:              False
__doc__ is a property method:              False
__eq__ is a property method:               False
__format__ is a property method:           False
__ge__ is a property method:               False
__getattribute__ is a property method:     False
__gt__ is a property method:               False
__hash__ is a property method:             False
__init__ is a property method:             False
__init_subclass__ is a property method:    False
__le__ is a property method:               False
__lt__ is a property method:               False
__module__ is a property method:           False
__ne__ is a property method:               False
__new__ is a property method:              False
__reduce__ is a property method:           False
__reduce_ex__ is a property method:        False
__repr__ is a property method:             False
__setattr__ is a property method:          False
__sizeof__ is a property method:           False
__str__ is a property method:              False
__subclasshook__ is a property method:     False
__weakref__ is a property method:          False
my_method is a property method:            False
my_property is a property method:          True
not_a_property is a property method:       False
Answered By: user3054622

To synthesize previous answers, here is a convenient function that returns the names of the properties of a class.

def get_properties_names(cls):
    return [k for k, v in vars(cls).items() if isinstance(v, property)]

So if you want the properties of an object obj, use:

props = get_properties_names(type(obj))
Answered By: Alexandre Huat
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.