使python __set__工作 - python

我只是想使用描述符模式,但似乎效果不佳。
这是一个简短的示例(没有任何实际用途,只是为了展示):

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