Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the Python descriptor __set__ not get called

Tags:

python

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__
like image 451
C Johnson Avatar asked Aug 08 '13 18:08

C Johnson


People also ask

What is __ set __ in Python?

The __set__() method is invoked when the value is set to the attribute, and unlike the __get__() method, it returns nothing. It has two arguments apart from the descriptor object itself, i.e., the instance which is the same as the __get__() method and the value argument, which is the value you assign to the attribute.

What is a Python descriptor?

Python descriptors are a way to create managed attributes. Among their many advantages, managed attributes are used to protect an attribute from changes or to automatically update the values of a dependant attribute. Descriptors increase an understanding of Python, and improve coding skills.

What is descriptor What is the purpose of descriptor?

A descriptor is a mechanism behind properties, methods, static methods, class methods, and super() . Descriptor protocol : In other programming languages, descriptors are referred to as setter and getter, where public functions are used to Get and Set a private variable.

What is descriptor object in Python?

Descriptors are Python objects that implement a method of the descriptor protocol, which gives you the ability to create objects that have special behavior when they're accessed as attributes of other objects.


1 Answers

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.

like image 162
martineau Avatar answered Sep 29 '22 18:09

martineau