Search code examples
pythondecoratorpython-decorators

Python: how to add a @classmethod @property.setter


This is a follow up question of Python: how to sum/multiply an int with the value of a @property

In the initial question I wanted to do arythmetic operations on the value of a property (which was related to a class attribute); I found out I had to define the property as a classmethod.

Now suppose I want to be able to change that property too, like in:

class A:
    __att = 3
    
    @classmethod
    @property
    def att(cls):
        return cls.__att
    
    """
    @classmethod
    @att.setter
    def att(cls, val):
        cls.__att = val
    """
    
    @classmethod
    def changeAtt(cls, val):
        cls.__att = val
        
    def test_method(self):
        return 3*A.att
        
a = A()
a.att = 5 #adding "att" to instance
print(a.test_method())
a.changeAtt(5)
print(a.test_method())

Output is

9
15

Tha method changeAtt do what I want, so it is something possible to accomplish, but if I try to uncomment the property setter, I get an error:

@att.setter AttributeError: 'classmethod' object has no attribute 'setter'

I also tried to invert the order of decorators, with no result. Again: what am I missing?


Solution

  • As chepner mentioned there are some restrictions in python to use @property with @classmethod and @xxx.setter.

    but there is a workaround using meta classes:

    class MyMetaClass(type):
        __att = 8
    
        @property
        def att(cls):
            return cls.__att
    
        @att.setter
        def att(cls, value):
            cls.__att = value
    
    class A(metaclass=MyMetaClass):
        pass
    
    
    print(A.att)
    

    this is working fine in python 3.10 and 3.11