Python:缓存描述符的值

时间:2015-01-29 13:05:20

标签: python descriptor

我想澄清一些关于Python描述符的事情。我想通过一些复杂的set / get机制向我的类添加一个属性,并在描述符对象中缓存这些计算值。一个简化的例子如下所示:

class Pro(object):
    """My descriptor class"""

    def __init__(self):
        self.value = None

    def __get__(self, instance, owner):
        return self.value

    def __set__(self, instance, value):
        self.value = value


class Something(object):
    """My simple class"""
    pro = Pro()

a = Something()
a.pro = 1

b = Something()
b.pro = 2

print(a.pro, b.pro) # At first, I've expected them to be 1 and 2

我认为,对于pro的每个实例,Pro属性都是Something的唯一实例,显然我错了。看起来我应该在instance._valueself.value内使用__set__而不是__get__,但我真的希望隐藏Pro类内的所有内容。这甚至可能吗?谢谢!

1 个答案:

答案 0 :(得分:3)

您的代码存在的问题是,您要在Pro的实例上设置属性,该属性将由Something的所有实例共享。要解决此问题,您应该在Something的单个实例上设置一个属性,一种方法是使用元类:

class Meta(type):
    def __new__(cls, name, bases, dct):
        for k, v in dct.items():
            if isinstance(v, Pro):
                # add an _ in front of the name
                v.name = '_' + k
        return super(Meta, cls).__new__(cls, name, bases, dct)


class Pro(object):

    def __get__(self, ins, typ):
        return getattr(ins, self.name)

    def __set__(self, ins, val):
            setattr(ins, self.name, val)

class Something(object):
    """My simple class"""
    __metaclass__ = Meta
    pro = Pro()

a = Something()
a.pro = 1

b = Something()
b.pro = 2

<强>演示:

>>> a.pro, b.pro
(1, 2)
>>> a.__dict__
{'_pro': 1}
>>> b.__dict__
{'_pro': 2}
>>> a.pro = 100
>>> a.__dict__
{'_pro': 100}

  

因此无法在Something中创建隐藏属性   实例,对吧?

不,有。您可以在Pro的实例中存储字典,该字典存储与Something的每个实例相关的所有值。例如,如果Something的实例是可清除的,那么您可以使用weakref.WeakKeyDictionary执行此类操作。 WeakKeyDictionary将确保一旦Something的实例没有引用,则会立即进行垃圾回收,这对于正常的dict是不可能的:

from weakref import WeakKeyDictionary

class Pro(object):

    def __init__(self):
        self.instances = WeakKeyDictionary()

    def __get__(self, ins, typ):
        return self.instances[ins]

    def __set__(self, ins, val):
        self.instances[ins] = val

p = Pro()

class Something(object):
    """My simple class"""
    pro = p

a = Something()
a.pro = 1

b = Something()
b.pro = 2

print a.pro, b.pro

print p.instances.items()
del a
print p.instances.items()

<强>输出:

1 2
[(<__main__.Something object at 0x7fb80d0d5310>, 1), (<__main__.Something object at 0x7fb80d0d5350>, 2)]
[(<__main__.Something object at 0x7fb80d0d5350>, 2)]