Python描述符在类之间共享值

3 投票
1 回答
927 浏览
提问于 2025-04-15 17:05

我正在使用一个Python描述符,它的值在所有实例之间共享。请问我该如何让每个实例的描述符拥有自己的内部值呢?

class Desc(object):
    def __init__(self, initval=None,name='val'):
        self.val = initval
        self.name = name

    def __get__(self,obj,objtype):
        return self.val

    def __set__(self,obj,val):
        self.val = val

    def __delete__(self,obj):
        pass


class MyClass(object):
    desc = Desc(10,'varx')

if __name__ == "__main__":
    c = MyClass()
    c.desc = 'max'
    d = MyClass()
    d.desc = 'sally'

    print(c.desc)
    print(d.desc)

输出结果是这样的,最后一次调用把两个对象的值都设置成了一样:

localhost $ python descriptor_testing.py 
sally
sally

1 个回答

7

这里只有一个描述符对象,它存储在类对象上,所以 self 总是指向同一个东西。如果你想为每个对象存储数据并通过描述符来访问这些数据,你要么得把数据存储在每个对象上(这可能是更好的选择),要么存储在一个以每个对象为键的数据结构中(我不太喜欢这个主意)。

我会把数据保存在实例对象上:

class Desc(object):
    default_value = 10
    def __init__(self, name):
        self.name = name

    def __get__(self,obj,objtype):
        return obj.__dict__.get(self.name, self.default_value)
        # alternatively the following; but won't work with shadowing:
        #return getattr(obj, self.name, self.default_value)

    def __set__(self,obj,val):
        obj.__dict__[self.name] = val
        # alternatively the following; but won't work with shadowing:
        #setattr(obj, self.name, val)

    def __delete__(self,obj):
        pass


class MyClass(object):
    desc = Desc('varx')

在这种情况下,数据会存储在 obj 的 'varx' 项目中,存在它的 __dict__ 里。不过,由于描述符查找的工作方式,你可以用描述符来“遮蔽”存储位置:

class MyClass(object):
    varx = Desc('varx')

在这种情况下,当你进行查找时:

MyClass().varx

描述符对象会被调用并进行查找,但当查找像这样进行时:

MyClass().__dict__['varx']

值会直接返回。因此,描述符能够把它的数据存储在一个“隐藏”的地方,可以这么说。

撰写回答