6

I have a descriptor on a class, and its __set__ method does not get called. I have been looking long and hard on this for a few hours and have no answer for this. But what I noticed below is that when I assign 12 to MyTest.X, it erases the property descriptor for X, and replaces it with the value of 12. So the print statement for the Get function gets called. That's good.

But the print statement for the __set__ function does NOT get called at all. Am I missing something?

class _static_property(object):
    ''' Descriptor class used for declaring computed properties that don't require a class instance. '''
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter

    def __get__(self, instance, owner):
        print "In the Get function"
        return self.getter.__get__(owner)()

    def __set__(self, instance, value):
        print "In setter function"
        self.setter.__get__()(value)

class MyTest(object):
    _x = 42

    @staticmethod
    def getX():
        return MyTest._x

    @staticmethod
    def setX(v):
        MyTest._x = v

    X = _static_property(getX, setX)


print MyTest.__dict__
print MyTest.X
MyTest.X = 12
print MyTest.X
print MyTest.__dict__
4
  • Are you sure you mean to use class attributes rather than instantiating an instance? Commented Aug 8, 2013 at 18:56
  • In my case which is very complicated, this is wrapping static methods, which ultimately gets passed down to C++ static methods. Commented Aug 8, 2013 at 19:00
  • At least SWIG had some issues with the descriptor protocols, so the solution might be in your C++ wrapping layer too, if you do more complex stuff than shown here. Commented Aug 12, 2013 at 19:07
  • Swig has complicated things, that is for sure. Commented Aug 12, 2013 at 22:22

3 Answers 3

6

The other two answers allude to using metaclasses to accomplish what you want to do. To help learn about them, here's an example of applying one to the code in your question that makes it do what you want:

class _static_property(object):
    """Descriptor class used for declaring computed properties that
       don't require a class instance.
    """
    def __init__(self, getter, setter):
        self.getter = getter
        self.setter = setter

    def __get__(self, obj, objtype=None):
        print("In the getter function")
        return self.getter(obj)

    def __set__(self, obj, value):
        print("In setter function")
        self.setter(obj, value)

class _MyMetaClass(type):
    def getX(self):
        return self._x

    def setX(self, v):
        self._x = v

    X = _static_property(getX, setX)

class MyTest(object):
    __metaclass__ = _MyMetaClass  # Python 2 syntax
    _x = 42

#class MyTest(object, metaclass=_MyMetaClass):  # Python 3 (only) syntax
#    _x = 42

print(MyTest.__dict__)
print(MyTest.X)
MyTest.X = 12
print(MyTest.X)
print(MyTest.__dict__)

Classes are instances of their metaclass which is normally type type. However you can use that as a base class and derive your own specialized meta-subclass -- that in this case is one that has class attributes which are data descriptors (aka properties). Note that the self argument in a meta or meta-subclass method is a metaclass instance, which is a class. In code above, it's named MyTest.

Sign up to request clarification or add additional context in comments.

Comments

5

Descriptors work on instances of classes, not classes themselves. If you had an instance of MyTest, X would work as you expect, but accessing it as a class attribute actually sets the attribute of the class object itself. You could try defining a custom metaclass to add the descriptor to, then creating MyTest with that metaclass.

1 Comment

Just to add, it is only the __set__ that requires an instance of the class. The __get__ can work on class as well. See this
3

The __set__ only gets called when you assign to X of an instance

If you want this to work for a class attibute, you'll have to set up the descriptor on the metaclass of MyTest

1 Comment

Is there anyway to make it do what I want?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.