1
class Cls():

    def __init__(self, start):
        self.value = start


    class Desc():
        def __get__(self, instance ,owner):
            print("In Descriptor's __get__method")
            return self.value
        def __set__(self, instance, start):
            print("In Descriptor's __set__ method")
            self.value = start

    value = Desc()

X = Cls('Hello')
X.value = "Hi"

描述符的上述实现对我来说是模糊的。X.value 和 Cls.value 引用同一个对象并且属于 str 类。但 Cls.__dict__['value'] 是描述符对象。有两种类型分配给名称“值”。

有人可以解释一下吗?这个特定实现背后的逻辑是什么。为什么 Cls.value 或 X.value 不是描述符对象。我正在使用 python 3.3

4

1 回答 1

4

您通过将名称value用于两件事来混淆事物:一个是 的属性Cls,其值是描述符对象。另一个是该描述符对象的属性,其值为字符串。

要记住的关键是只有一个描述符对象,在类的所有实例之间共享。当您self.value = start__set__方法中执行时,self指的是描述符对象,因此您在描述符对象本身上设置“值”属性,而不是在Cls实例上。(如果你改为instance.value = start改为,你会得到一个递归错误,因为它会尝试__set__再次调用。)

如果您创建类的多个实例,您将看到发生了什么:

>>> x = Cls("oops")
In Descriptor's __set__ method
>>> y = Cls("dang")
In Descriptor's __set__ method
>>> x.value
In Descriptor's __get__method
'dang'
>>> Cls.__dict__['value'].value
'dang'

请注意,创建已y更改x.value。这是因为只有一个描述符对象,并且它只有一个“值”属性,因此该值在所有Cls.

目前尚不清楚您要在这里实现什么目标,因此很难说如何“解决”这个问题。一些一般原则是:

  1. 除非你想存储类级别的信息,否则不要使用selfin 。要存储特定于实例的数据,您需要使用.__get____set__instance
  2. 即使你做了上面的事情,也不要对描述符属性本身和它存储数据的隐藏属性使用相同的名称,否则你会踩到自己的脚趾。
  3. 除非您想做一些真正花哨的事情,否则您可能只使用property而不编写自己的描述符。如果您“修复”了您在上面编写的描述符,它仍然是无用的,因为它不会做任何property尚未做的事情。
于 2013-10-06T04:41:24.663 回答