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?

Kyle Wild
  • 8,845
  • 2
  • 36
  • 36

5 Answers5

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.

sunny
  • 530
  • 1
  • 6
  • 12
Andrew Clark
  • 202,379
  • 35
  • 273
  • 306
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)]
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
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)]
3

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

Jonathan Scholbach
  • 4,925
  • 3
  • 23
  • 44
  • 1
    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. – user2357112 Jan 21 '21 at 10:26
  • This was also pointed out here: https://stackoverflow.com/questions/5876049/in-a-python-object-how-can-i-see-a-list-of-properties-that-have-been-defined-wi/65825416#comment17809207_5876258 – jonrsharpe Jan 21 '21 at 10:45
  • @user2357112supportsMonica Ah, yes. You are right. I updated the answer accordingly. Thank you. – Jonathan Scholbach Jan 21 '21 at 11:08
0

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

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • 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. – Kyle Wild May 03 '11 at 21:48