Reputation: 149
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.
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)
>>> 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
.
Upvotes: 0
Views: 1162
Reputation: 51034
From the docs:
object.__set__(self, instance, value)
Called to set the attribute on an instance
instance
of 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
Upvotes: 1