我只是想使用描述符模式,但似乎效果不佳。
这是一个简短的示例(没有任何实际用途,只是为了展示):
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
和测试:
>>>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
我的误解是什么?
python大神给出的解决方案
描述符仅在它们是类的属性而不是实例的属性时才起作用。如果您将课程更改为:
class Test(object):
num = Num()
。 。 。那么描述符将起作用。
但是,由于必须在类上设置描述符,所以这意味着描述符只有一个实例,因此将描述符的值存储在self
上可能不是一个好主意。这些值将在该类的所有实例之间共享。而是在instance
上设置值。
另外,请注意,您的__str__
和__repr__
可能不会执行您认为会做的事情。调用t.num
将激活描述符并返回其val
,因此t.num
的结果将为纯数字0,而不是Num
实例。描述符的全部目的是透明地返回__get__
的结果,而不会使描述符对象本身可见。
以下是一些说明性示例:
>>> t1 = Test()
>>> t2 = Test()
>>> t1.num
0
>>> Test.num
0
# Accessing the descriptor object itself
>>> Test.__dict__['num']
Num(0)
>>> t1.num = 10
>>> t1.num
10
# setting the value changed it everywhere
>>> t2.num
10
>>> Test.num
10
使用描述符的备用版本:
class Num(object):
def __init__(self, val=0):
self.val = val
def __get__(self, instance, owner):
try:
return instance._hidden_val
except AttributeError:
# use self.val as default
return self.val
def __set__(self, instance, val):
instance._hidden_val = val
class Test(object):
num = Num()
>>> t1 = Test()
>>> t2 = Test()
>>> t1.num
0
>>> t1.num = 10
>>> t1.num
10
# Now there is a separate value per instance
>>> t2.num
0