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__
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.
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.
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.
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With