In a Python object, how can I see a list of properties that have been defined with the @property decorator?
Asked Answered
O

5

18

I can see first-class member variables using self.__dict__, but I'd like also to see a dictionary of properties, as defined with the @property decorator. How can I do this?

Ourself answered 3/5, 2011 at 21:39 Comment(0)
A
21

You could add a function to your class that looks something like this:

def properties(self):
    # class_items = self.__class__.__dict__.iteritems()  # Python 2
    class_items = self.__class__.__dict__.items()
    return dict((k, getattr(self, k)) 
                for k, v in class_items 
                if isinstance(v, property))

This looks for any properties in the class and then creates a dictionary with an entry for each property with the current instance's value.

Adherence answered 3/5, 2011 at 22:1 Comment(4)
Be aware that this only lists properties declared on the class itself IIRC. Properties of superclasses will not be listed.Knoll
You can walk self.__class__.mro() to find parent classes.Mithgarthr
A one-liner would be return {k: getattr(self, k) for k, v in self.__class__.__dict__.iteritems() if isinstance(v, property)}Grilled
for python 3, replace iteritems() with items()Sonorous
R
8

The properties are part of the class, not the instance. So you need to look at self.__class__.__dict__ or equivalently vars(type(self))

So the properties would be

[k for k, v in vars(type(self)).items() if isinstance(v, property)]
Randy answered 3/5, 2011 at 21:59 Comment(0)
S
4

As user2357112-supports-monica points out in a comment to a duplicate question, the accepted answer only gets those properties directly defined on the class, missing inherited properties. In order to fix this, we also need to walk over the parent classes:

from typing import List


def own_properties(cls: type) -> List[str]:
    return [
        key
        for key, value in cls.__dict__.items()
        if isinstance(value, property)
    ]

def properties(cls: type) -> List[str]:
    props = []
    for kls in cls.mro():
        props += own_properties(kls)
    
    return props

For example:

class GrandparentClass:
    @property
    def grandparent_prop(self):
        return "grandparent_prop"   


class ParentClass(GrandparentClass):
    @property
    def parent_prop(self):
        return "parent"


class ChildClass(ParentClass):
    @property
    def child_prop(self):
        return "child"


properties(ChildClass)  # ['child_prop', 'parent_prop', 'grandparent_prop']

If you need to get the properties of an instance, simply pass instance.__class__ to get_properties

Swiss answered 21/1, 2021 at 10:23 Comment(3)
You should traverse cls.__mro__ instead of recursing over cls.__bases__, to handle diamond inheritance properly. Recursing over cls.__bases__ may visit some ancestors repeatedly.Feder
This was also pointed out here: #5876549Recurrent
@user2357112supportsMonica Ah, yes. You are right. I updated the answer accordingly. Thank you.Swiss
F
3

For an object f, this gives the list of members that are properties:

[n for n in dir(f) if isinstance(getattr(f.__class__, n), property)]
Flemming answered 3/5, 2011 at 22:9 Comment(0)
O
0

dir(obj) gives a list of all attributes of obj, including methods and attributes.

Obmutescence answered 3/5, 2011 at 21:46 Comment(1)
Right, but I need to know the properties specifically. I considered overwriting the @property decorator to add them to a registry on obj, but I figured Python probably has a fancy __something__ that already does this.Ourself

© 2022 - 2024 — McMap. All rights reserved.