I’m new to using descriptors and I think I have a good understanding on how they work but I have come across a problem and i’m not sure how to fix it.
Code
class Foo:
class Bar:
def __get__(self,instance, owner):
return 10
def __set__(self,instance,value):
raise Exception
bar=Bar()
print(Foo.bar)
Foo.bar=5
print(Foo.bar)
Output
>>> 10 >>> 5
Im trying to make bar a constant for testing purposes, I know about the property decorator but I prefer using descriptors.
First I print out the value of bar to see if __get__ works – and it does, the output is 10.
But then when I assign 5 to bar the expected result would be an exception but instead what happens is 5 gets assigned to bar despite specifying __set__ so when I print again the second output is 5.
Can someone tell me why the error isn’t being raised?
Advertisement
Answer
From the docs:
object.__set__(self, instance, value)Called to set the attribute on an instance
instanceof the owner class to a new value,value.
In your code, Foo.bar = 5 is setting the class attribute, not an instance attribute. If you do use an instance (without first setting Foo.bar = 5, which overrides your descriptor), then you get an exception as expected:
>>> f = Foo() >>> f.bar 10 >>> f.bar = 5 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 6, in __set__ Exception
If you want the __set__ behaviour to apply when the class attribute is set, then the class itself needs to be an instance of a metaclass which uses the descriptor:
class FooMeta(type):
class Bar:
def __get__(self,instance, owner):
return 10
def __set__(self,instance,value):
raise Exception
bar = Bar()
class Foo(metaclass=FooMeta):
pass
Testing:
>>> Foo.bar 10 >>> Foo.bar = 5 Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 6, in __set__ Exception