I just wanted to use the descriptor pattern, but it didn't seem to work that well. Here is a short example (without any real use, just to show):
class Num(object):
def__init__(self, val=0):
self.val = val
def __get__(self, instance, owner):
return self.val
def __set__(self, instance, val):
self.val = val
def __str__(self):
return "Num(%s)" % self.val
def __repr__(self):
return self.__str__()
class Test(object):
def __init__(self, num=Num()):
self.num = num
and the Test:
>>>t = Test()
>>>t.num # OK
Num(0)
>>>t.num + 3 #OK i know how to fix that, but I thought __get__.(t.num, t, Test) will be called
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'Num' and 'int'
>>> t.num = 4 # why isn't __set__(t.num, t, 4) called here?
>>> t.num
4
What is my misconception here?
Descriptors only work when they are attributes of a class, not an instance. If you change your class to:
. . . then the descriptor will work.
However, because the descriptor has to be set on the class, that means there is only one instance of the descriptor, so it's probably not a good idea for the descriptor to store its values on
self
. Such values will be shared across all instances of the class. Instead, set the value oninstance
.Also, note that your
__str__
and__repr__
will probably not do what you think they will. Callingt.num
will activate the descriptor and return itsval
, so the result oft.num
will be the plain number 0, not aNum
instance. The whole point of the descriptor is to transparently return the result of__get__
without making the descriptor object itself visible.Here are some illustrative examples:
With an alternate version of the descriptor: