8

I need to list all the attribute of a class that are properties and have a setter. For example with this class:

class MyClass(object):
    def __init__(self):
        self. a = 1
        self._b = 2
        self._c = 3

    @property
    def b(self):
        return self._b

    @property
    def c(self):
        return self._c

    @c.setter
    def c(self, value):
        self._c = value

I need to get the attribute c but not a and b. Using this answers: https://stackoverflow.com/a/5876258/7529716 i can get the property object b and c.

But is their a way to know if those properties have a setter other than trying:

inst = MyClass()    
try:
    prev = inst.b
    inst.b = None
except AttributeError:
    pass # No setter
finally:
    inst.b = prev  

Thanks in advance.

Yassine Faris
  • 951
  • 6
  • 26

1 Answers1

11

property objects store their getter, setter and deleter in the fget, fset and fdel attributes, respectively. If a property doesn't have a setter or deleter, the attribute is set to None.

This means you can simply filter out those properties whose fset attribute is set to None:

def get_writeable_properties(cls):
    return [attr for attr, value in vars(cls).items()
                 if isinstance(value, property) and value.fset is not None]
>>> get_writeable_properties(MyClass)
['c']
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
  • You can make this even better and support not only class arguments but also instances. You would get the `obj.__class__` if `inspect.isclass(obj)` yields `False` – Matias Cicero Apr 20 '18 at 14:16
  • 1
    @MatiasCicero I don't think that's a good idea, because of metaclasses. Classes are also instances. I don't like to guess what the user wants; I'd rather write a function that only works on classes or only on instances. – Aran-Fey Apr 20 '18 at 14:20