Python:缓存描述符的值

Python:缓存描述符的值,python,descriptor,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 de

我想澄清一些关于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
的唯一实例,对于
某物的每个实例,显然我错了。看起来我应该使用类似于
instance.\u value
的东西,而不是
self.value
\u set\u
\u get\u
中,但是我真的希望把所有东西都隐藏在
Pro
类中。这可能吗?谢谢

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

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}
1 2
[(<__main__.Something object at 0x7fb80d0d5310>, 1), (<__main__.Something object at 0x7fb80d0d5350>, 2)]
[(<__main__.Something object at 0x7fb80d0d5350>, 2)]


所以在某些东西中没有办法隐藏属性 实例,对吗

不,有。您可以在
Pro
的实例中存储字典,该字典存储与
某物的每个实例相关的所有值。例如,如果
某物的实例是可散列的,那么您可以使用。
WeakKeyDictionary
将确保一旦某个
某物的实例没有剩余引用,它将立即被垃圾收集,这是正常的
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()
输出:

>>> a.pro, b.pro
(1, 2)
>>> a.__dict__
{'_pro': 1}
>>> b.__dict__
{'_pro': 2}
>>> a.pro = 100
>>> a.__dict__
{'_pro': 100}
1 2
[(<__main__.Something object at 0x7fb80d0d5310>, 1), (<__main__.Something object at 0x7fb80d0d5350>, 2)]
[(<__main__.Something object at 0x7fb80d0d5350>, 2)]
12
[(, 1), (, 2)]
[(, 2)]

你看了吗?@Lemming,看起来很整洁,谢谢,但我只希望用标准库来解决这个问题:)很公平。顺便说一句,与大多数python包一样,这一个是开源的。非常小,非线程版本不需要任何额外的包。源代码很有趣,谢谢,直到现在才看到它。所以在
Something
实例中没有办法隐藏属性,对吗?如果要“缓存”实例的值,该值必须与实例关联。Python属性基本上是通过使用对象的dict字典来实现的。您可以通过在描述中使用实例作为键的字典来逆转它,但基本问题仍然是您需要实例到值的映射,反之亦然versa@AntonMelnikov当然这也是可能的,请参阅更新。@AshwiniChaudhary好的,我想我现在明白了。谢谢你的解释。